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)
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;
}
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
}
References
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
Core Data Does Not React on Changed Predicate
Please Clear Some Confusions Regarding Uiviewcontroller
iOS Rich Notification Didreceivenotificationrequest Is Not Fired
Calculate Uitableviewcell Height to Fit String
How to Analyze Stack Trace Info of a Thread
How to Run Timer Though the App Entered Background or Is Terminated
How to Intercept Push Notifications for Another App
How to Parse This JSON in Swift
Why I Couldn't Assign Fetched Values from Firestore to an Array in Swift
How to Use Git Properly with Xcode
iPad Multitasking Support Requires These Orientations
Differences Between Websockets and Long Polling for Turn Based Game Server
Disable the Interactive Dismissal of Presented View Controller
Where Should I Be Setting Autolayout Constraints When Creating Views Programmatically
Uicollectionview Performance - _Updatevisiblecellsnow