11

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.

AndroC
  • 4,758
  • 2
  • 46
  • 69
  • May be something related to UIViewController's setAutomaticallyAdjustsScrollViewInsets api on iOS7 – Bilal Saifudeen May 23 '14 at 12:15
  • I set automaticallyAdjustsScrollViewInsets = NO; on every view controller I thought might be relevant to the situation. It does not help. – AndroC Jun 03 '14 at 07:57
  • I met this problem as well. I manually set contentOffset as (0,-64),but _adjustContentOffsetIfNecessary changed it to -108 again. Confused. Any update? – Wingzero Apr 28 '15 at 08:30
  • No, no update yet... If I will have time, I'll try to recreate the problem in a sample app and then post a link to git repository here... – AndroC Apr 28 '15 at 13:22
  • Have y solve this problem yet? I met this problem as well when using autolayout... – ylovesy May 19 '16 at 06:48
  • Long tims since I did iOS, but I believe it could have something to do with the following. If you have multiple UIScrollView's on view hierarchy, make sure that only one or none of them has `scrollsToTop` property set to true. – AndroC May 21 '16 at 13:57
  • @ancajic, im also facing the same issue. I have only one scrollview at the page and have a map view within that. I even set 'scrollsToTop = false'. But when i tap anywhere in the screen after scrollling down, it is automatically moves top of the page. Any idea....? – Abirami Bala Nov 28 '16 at 06:15

3 Answers3

1

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

voiger
  • 781
  • 9
  • 19
  • That does not seem to work on iOS 12.3. Tried adding dummy views all over the place around the UICollectionView (so that it's not a main and not first one, not last one, ...), but _adjustContentOffsetIfNecessary gets called every time when collectionView reloads. – uson1x Jun 24 '19 at 08:04
1

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
    }
}
  • 1
    alternatively you can override contentOffset property guard window != nil else {return} super.contentOffset = newValue – clatt Dec 08 '20 at 13:43
  • @clatt Yeah, that can works too, if you already use class, that inherits UIScrollView. Provided by me solution allows to work with standard UIScrollView and define offset behavior in specified UIView element – Дмитрий Ванюшкин Dec 15 '20 at 08:40
0

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

nguyenbao95
  • 31
  • 1
  • 4