UIScrollView adjusts contentOffset when contentSize changes

旧城冷巷雨未停 提交于 2019-11-28 03:49:20

Occurs when pushing a UIViewController containing a UIScrollView using a UINavigationController.

iOS 7

Solution 1 (Code)

Set @property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets to NO.

Solution 2 (Storyboard)

Uncheck the Adjust Scroll View Insets

iOS 6

Solution (Code)

Set the UIScrollView's property contentOffset and contentInset in viewWillLayoutSubviews. Sample code:

- (void)viewWillLayoutSubviews{
  [super viewWillLayoutSubviews];
  self.scrollView.contentOffset = CGPointZero;
  self.scrollView.contentInset = UIEdgeInsetsZero;
}

The cause of this problem remains unclear, though I've found a solution. By resetting the content size and offset before adjusting them, the UIScrollView won't animate:

- (void)detailsForObject:(id)someObject {
    // These 2 lines solve the issue:
    self.scrollView.contentSize = CGSizeZero;
    self.scrollView.contentOffset = CGPointZero;

    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}

I had the same issue with a UIScrollview, where the problem was caused by not setting the contentSize. After setting the contentSize to the number of items this problem was solved.

self.headerScrollView.mainScrollview.contentSize = CGSizeMake(320 * self.sortedMaterial.count, 0);

Here's what worked for me:
In the storyboard, in the Size Inspector for the scrollView, set Content Insets Adjustment Behavior to "Never".

Is your scrollView the root view of the DetailViewController? If yes, try wrapping the scrollView in a plain UIView and make the latter the root view of DetailViewController. Since UIViews don't have a contentOffset property, they are immune to content offset adjustments made by the navigation controller (due to the navigation bar, etc.).

Balázs Csordás

I experienced the problem, and for a specific case - I don't adjust the size - I used the following:

float position = 100.0;//for example

SmallScroll.center = CGPointMake(position + SmallScroll.frame.size.width / 2.0, SmallScroll.center.y);

Same would work with y: anotherPosition + SmallScroll.frame.size.height / 2.0

So if you don't need to resize, this is a quick and painless solution.

I was experiencing a similar problem, where UIKit was setting the contentOffset of my scrollView during push animations.

None of these solutions were working for me, maybe because I was supporting iOS 10 and iOS 11.

I was able to fix my issue by subclassing my scrollview to keep UIKit from changing my offsets after the scrollview had been removed from the window:

/// A Scrollview that only allows the contentOffset to change while it is in the window hierarchy. This can keep UIKit from resetting the `contentOffset` during transitions, etc.
class LockingScrollView: UIScrollView {
    override var contentOffset: CGPoint {
        get {
            return super.contentOffset
        }
        set {
            if window != nil {
                super.contentOffset = newValue
            }
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!