Shifting view after displaying modal - possibly Au

2019-01-12 05:05发布

问题:

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

回答1:

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



回答2:

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;
        });
    }
}