Bounds automatically changes on UIScrollView with content insets

后端 未结 5 679
傲寒
傲寒 2020-12-28 22:54

I\'m using a UIScrollView as my paging scroll view, pagesScrollView. Inside that, I put individual UIScrollViews which are used exclusively for zooming. Inside

5条回答
  •  一个人的身影
    2020-12-28 23:57

    It's an iOS bug. I created the following subclass of UIScrollView to get a log of what happens to y over time and who was pushing it:

    @implementation CSScrollView
    
    - (void)setContentOffset:(CGPoint)contentOffset
    {
        NSLog(@"%0.0f %@", contentOffset.y, [NSThread callStackSymbols]);
        NSLog(@"[%@]", self.layer.animationKeys);
        [super setContentOffset:contentOffset];
    }
    
    @end
    

    (and changed the view class in the storyboard)

    When you release your finger, a method called UIScrollView _smoothScrollDisplayLink: starts animating the scroll view to its final position. As per the second log, there's no CAAnimation involved, the scroll view uses its own display link to do its own transition. That custom code appears to make the mistake of animating from y = whatever to y = 0, failing to take the content offset into account.

    As a proof-of-concept hack I changed the code to:

    @implementation CSScrollView
    
    - (void)setContentOffset:(CGPoint)contentOffset
    {
        contentOffset.y = -64.0f;
        [super setContentOffset:contentOffset];
    }
    
    @end
    

    And, unsurprisingly, the problem went away.

    You probably don't want to hard code the -64.0f but I'd conclude:

    • it's an iOS bug;
    • work around it by rejecting nonsensical values via a subclass of UIScrollView with a suitable custom implementation of - setContentOffset:.

    A sensible generic means might be to check the state of self.panGestureRecognizer — that'll allow you to differentiate between scrolls the user is responsible for and other scrolls without relying on any undocumented API or complicated capturing of delegate events. Then if necessary crib the correct contentOffset.y from the current value rather than hardcoding it.

提交回复
热议问题