Autolayout is changing UIScrollView's contentOffset on rotation

北慕城南 提交于 2019-12-21 13:03:08

问题


To experiment with autolayout and uiscrollview's I have been using this example

which I have edited to include 2 views in the scroll view, I have setup the autolayout constraints to position the views horizontally adjacent with their size set to fill the scroll view frame.

UIView *beeView = [[[NSBundle mainBundle] loadNibNamed:@"BeeView" owner:nil options:nil] firstObject];
beeView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:beeView];
UIView *beeView2 = [[[NSBundle mainBundle] loadNibNamed:@"BeeView" owner:nil options:nil] firstObject];
beeView2.backgroundColor= [UIColor orangeColor];
beeView2.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:beeView2];

NSDictionary *views = @{@"beeView":beeView,@"beeView2":beeView2, @"scrollView":self.scrollView};
NSDictionary *metrics = @{@"height" : @200};
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[beeView(==scrollView)][beeView2(==beeView)]|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:metrics views:views]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[beeView(==scrollView)]|" options:kNilOptions metrics:metrics views:views]];

which nicely produces what I intended.

However, if the scroll view's contentOffset is nonzero and the device is rotated from portrait to landscape, the content offset of the scroll view is automatically set to 32px. (see screenshot)

I have tried saving contentOffset and setting it to this saved value when scrollViewDidEndDecelerating: is called which works but is ugly as the scroll view scrolls to a 32px offset and then back to where I want it to be.

How do I control the scroll view's contentOffset? Are the autolayout constraints wrong? Are there extra constraints I can add to control the contentOffset when resizing the view?


回答1:


Where the 32px comes from? Is it related to your left and right scrollView margin?

Does it keep the wrong offset every time you change page ? If that the case, you should look at your scrollView's contentInsets values.

Otherwise, what I do to manage rotation on scrollView with paging is observing the scrollView's contentSize:

First, when you load the view, add the observer:

[self.scrollView addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize)) options:0 context:nil];

Then, when the contentSize value change, adjust the contentOffset:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if (object == self.scrollView && [keyPath isEqualToString:NSStringFromSelector(@selector(contentSize))]) {

        //Note that you should track your page index
        self.scrollView.contentOffset = CGPointMake(self.pageIndex * self.scrollView.bounds.size.width, self.scrollView.contentOffset.y);

    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Finally, remove the observer when you unload the scrollView:

[self.scrollView removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize)) context:nil];



回答2:


After referring back to a few previous posts: one & two. It seems you might find your solution following one of these steps:

  1. Programmatically : If your UIScrollViews' parent VC is not directly on the Nav Stack -

~Edit~

    // Without a Navigation Controller

    self.automaticallyAdjustsScrollViewInsets = NO;

    // With a Navigation Controller

    self.parentViewController.automaticallyAdjustsScrollViewInsets = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;
  1. Interface Builder : Attributes Inspector -> Uncheck Adjust Scroll View Insets in the Layout Properties.

  2. IF Still Unsuccessful : Within the presented View Controller's ViewWillLayoutSubviews Method try setting each of the following UIScrollView properties:

    self.scrollView.contentOffset = CGPointZero;
    self.scrollView.contentInset = UIEdgeInsetsZero;
    

I am guessing a combination of option 1 and 2 will work, depending on how your Navigation Stack is structured.




回答3:


For iOS 11.0 and greater, the following method solves the issue for me:

if (@available(iOS 11.0, *))
{
    self.myScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}



回答4:


I know this is an old question, but in case it is of use to anyone - I have created a subclass of UIScrollView called LMPageView that automatically applies the necessary layout constraints and adjusts the content offset on rotation. The class is available as part of the MarkupKit project on GitHub. Example usage (Swift):

// Add 3 page views
pageView.addPage(view1)
pageView.addPage(view2)
pageView.addPage(view3)

// Show the 3rd page
pageView.currentPage = 2

An additional example that uses markup to initialize a page view can be found here:

  • PageViewController.swift
  • PageViewController.xml


来源:https://stackoverflow.com/questions/31844493/autolayout-is-changing-uiscrollviews-contentoffset-on-rotation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!