I present a simple view with a couple of labels and a button, all inside a UIScrollView
and laid out using auto layout.
The button presents another view, which includes a navigation item for dismissal.
After dismissal, though, the content of the original UIScrollView
is offset. Strangely, the amount by which it is offset seems related to the scroll position at the time of presentation.
The demo project here is a small example of this issue. Run it in the iPhone simulator and scroll to the bottom to use the 'modal' button. After dismissing the modal attempt to scroll back to the top - the issue should be clear.
Or refer to the scroll bar in the images below to see the problem.
BEFORE PRESENTATION
AFTER PRESENTATION
I'm not an expert in AutoLayout, but I fixed it by adding the label & button constraints to self.view
instead of self.scrollView
.
For example:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[l1]"
options:0
metrics:nil
views:@{@"l1":self.l1}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[l1]"
options:0
metrics:nil
views:@{@"l1":self.l1}]];
Why this fixes it... have no idea :D
I've had this same problem, and after much investigation it appears to be a bug in UIKit relating to scrollviews and AutoLayout. Here's the 'fix'...
In viewDidDisappear:
, save the current scrollview contentOffset
to a property, and reset it to zero:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.previousContentOffset = self.scrollView.contentOffset;
self.scrollView.contentOffset = CGPointZero;
}
Then, in viewWillAppear:
, reset the content offset back to what it was previously. I had to dispatch this onto the main queue to get it to work correctly:
- (void)viewWillAppear:(BOOL)animated
{
if (!CGPointEqualToPoint(self.previousContentOffset, CGPointZero))
{
dispatch_async(dispatch_get_main_queue(), ^{
self.scrollView.contentOffset = self.previousContentOffset;
});
}
}