2

I want to scroll to the top of a UIScrollView. You have two possibilities:

  • setContentOffset()
  • scrollView.contentOffset

If I use an animation then the scrollview sometimes scrolls to (0, -26) instead of (0, 0). So it scrolls further but then doesn't go back to (0, 0). This currently happens on iPad only.

If I don't use an animation this works everytime as expected. Has somebody a clue what is wrong here? I tested this on iPad 2 iOS 8.4 simulator

Edit:

Before I made my call with setContentOffset() I had this:

scrollView.layoutIfNeeded();
scrollView.setContentOffset(somePosition, true);

Removing layoutIfNeeded also removes the problem. But why?

Note: I wasn't calling setContentOffset() multiple times consecutively. That are completely different tasks!

testing
  • 17,950
  • 38
  • 208
  • 373
  • Do you change anything else like insets? And as usual, posting essential lines of code may help to help you. – meaning-matters Feb 16 '16 at 15:31
  • I don't change the insets, only the content offset. The only thing I do before scrolling is that I add some new items to the scroll view. The code line itself is very simple by setting the content offset (nothing more). But there is something else in my complex project, which seems to have this effect. When I scroll to top with the help of a button (completely independent of the things I add to the scroll view before), this also works perfectly with animation. So perhaps this is an timing issue. – testing Feb 16 '16 at 15:49
  • 1
    It does sound like a timing problem. Layout takes time. Animation takes time. So what will happen when you say both? Saying `layoutIfNeeded` is actually not a very common thing to do (there are certain very special situations where it is correct). I wonder why you're doing it... also I wonder vaguely whether reversing the order of those two lines would help. – matt Feb 16 '16 at 16:04
  • @matt: I had this because of another problem. Here I changed the content offset very early (from `layoutSubviews`). The app crashed without this. Now I'm checking if I still need this. – testing Feb 16 '16 at 16:06
  • @matt: Reversing the order of the two lines also seems to work. – testing Feb 16 '16 at 16:10
  • 1
    @testing Do you want me to add that as a suggestion to my answer? I'm not really solving the problem, just showing you the sort of thing I do when, as you have rightly deduced, there seems to be a timing issue. — Added it. – matt Feb 16 '16 at 16:42

1 Answers1

4

Try it this way:

scrollView.layoutIfNeeded();
delay(0.05) {
    scrollView.setContentOffset(somePosition, true);
}

(where delay is here: dispatch_after - GCD in swift?)

My idea is that this might give layout time to happen before we proceed.

Another idea might be to try reversing the order of those two line:

scrollView.setContentOffset(somePosition, true);
scrollView.layoutIfNeeded();

The idea here is that layout will take place during the animation, and we know that layout is designed to work during animation (that is why layout changes during rotation are animated, for example).

Community
  • 1
  • 1
matt
  • 447,615
  • 74
  • 748
  • 977
  • I tried to use the delay, but that didn't worked for me. Reversing the order seems the way to go. What should also work is to place the `layoutIfNeeded` in `layoutSubviews` (but it should only called one time). – testing Feb 16 '16 at 17:00