_adjustContentOffsetIfNecessary - UIScrollView automatically scrolls to top

2.8k views Asked by At

On iOS 7. I have navigation controller and I push a new VC on top of the stack.

That new VC has a UIScrollView that fills the VC's root view and scrolls vertically. If I scroll down a little bit and then try to use 'swipe to go back' / 'swipe to pop' gesture, the vertical scroll view first scrolls to top, and then the interactivePopGesture is recognized and I can drag the top VC on the stack left and right.

Why does this happen? I wish to prevent my scroll view from automatically scrolling to the top before 'swipe to go back' gesture is recognized. How do I do this?

UPDATE #1:

I cannot seem to reproduce this bug when I create a fresh xcode project, so it is most certainly error on my part in the original project. Will update when I find the reason.

UPDATE #2:

When interactivePopGesture gets recognized, setContentOffset method is called on my vertical scroll view. While debugging, I see that setContentOffset was invoked from UIScrollViewInternal _adjustContentOffsetIfNecessary.

UPDATE #3:

Same problem happens in a following scenario: I have UITextFields inside a vertical UIScrollView. When a certain UITextField is pressed, a keyboard appears. When I want to dismiss the keyboard interactively (by dragging on scroll view over the keyboard), after I release the drag, a glitch happens. UIScrollView's content offset has momentarily been set to zero, and then set back to original content offset and proceeded with the animation. This unwanted setting of contentOffset is also invoked by UIScrollViewInternal _adjustContentOffsetIfNecessary.

I went ahead and replaced the UIScrollView in both scenarios with my own subclass of UIScrollView. In that subclass I overridden a private method -(void) _adjustContentOffsetIfNecessary as a empty void method. Both of my problems were eliminated, and I could not find any negative consequences. This is not a solution and I will not use this approach, since I have no idea what exactly I have done.

3

There are 3 answers

0
nguyenbao95 On

Use UIViewController with a UITableView instead of UITableViewController. It solved my problem :)

1
voiger On

I've found an interesting discussion about this on Twitter. Though it's not my case, it might help somebody:

Is there some trick to bring UINavigationController to not mess with a UIScrollView  (_adjustContentOffsetIfNecessary)?

@steipete Searching for the same thing and came across your tweet. I set contentOffset but it resets back to -64 (ios7). Did you find a fix?
 @errthling Add a dummy view as first subview. It won’t look further.
 @steipete Wow – that worked. I've been struggling with it for days. Thanks for that and everything else you put out there! :)
 @errthling happy to help!

@steipete did you find an answer to this, 2 years ago? =D my scrollview's contentOffset is reset when I push a new viewcontroller..
 @manuelmaly Yeah. Changed the view hierarchy so the scroll view is not the main view and not the first subview, and UIKit stops messing.
 @steipete oO i hacked it in the meantime by blocking setContentOffset before pushViewController is called. your solution seems cleaner tho

twitter discussion

2
Дмитрий Ванюшкин On

I meet with same problem in iOS 14. Looks like no normal way to prevent call of _adjustContentOffsetIfNecessary. Overriding didMoveToWindow() in problem view helps me

override func didMoveToWindow() {
    super.didMoveToWindow()
    // window == nil when new screen pushed
    if window == nil {
        // Set correct offset that was before
    }
}