Uiscrollview Adjusts Contentoffset When Contentsize Changes

UIScrollView adjusts contentOffset when contentSize changes

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

iOS 11+

Solution 1 (Swift Code):

scrollView.contentInsetAdjustmentBehavior = .never

Solution 2 (Storyboard)

Sample Image

iOS 7

Solution 1 (Code)

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

Solution 2 (Storyboard)

Uncheck the Adjust Scroll View Insets

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;

Autolayout is changing UIScrollView's contentOffset on rotation

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];

UIScrollView change contentOffset when change frame

I found out that is a private method that is causing that => _adjustContentOffsetIfNecessary

It change the offset in some cases and don't change in others. Like I explained in my example.

That private method isn't called if the paging is disabled so to solve my problem I created a subclass of UIScrollView and overwrite the method touchesShouldBegin (it is called only when the button inside scrollView is pressed) and disable the paging:

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
[self setPagingEnabled:NO];
return YES;

To set the paging enabled again, I use the delegate scrollViewWillBeginDragging.

Doing that, the contentOffset don't change when I change the frame and the scrollView continues to work with paging.

UIScrollview contentOffset changes when removed from window

Kind of a hack, but you can put a test in your setContentOffset: and simply return if it has already been removed from its superview.

Does the UIScrollView automatically adjust contentOffset to fit inside the safe area?

UIScrollView has a property where it "insets" the content so that the safe areas are not overlapped.

It can be changed by setting setting the contentInsetAdjustmentBehavior property of the UIScrollView instance like so:

scrollView.contentInsetAdjustmentBehavior = .never

Note that it is not the contentOffset, but contentInset that gets adjusted. This is why the content offset is still (0, 0) in all cases.

Also, if you are building for an iOS Development Target lower than iOS 11.0, you might get a build error. In that case you can use the following code instead.

if #available(iOS 11.0, *){
scrollView.contentInsetAdjustmentBehavior = .never


Apple Developer Docs - contentinsetadjustmentbehavior

UIScrollView contentOffset change after another view pushed

See my answer to a similar question.

You need to set the scrollview's contentOffset appropriately in viewWillAppear: and viewWillDisappear:.

Also, see this:

  • This answer to the question UIScrollView's origin changes after popping back to the UIViewController.
  • This related question, UIScrollview Autolayout Issue.

UIScrollView - setting proper contentOffset for new contentSize yields undesirable empty space

The origin is always (0,0). If you want to insert something above the current offset you'll want to move the current views down by 480 points, add the new view at (0,0) and set the contentOffset to (0,480) (and the contentSize to (320,960).

Related Topics

Leave a reply