滚动快速后,粘滞滚动视图子视图的帧不正确.可编辑的例子

use*_*ser 5 iphone objective-c uiscrollview uiview ios

过去12个小时,我已经花了这么多时间,而且我要去脑海.

在bitbucket上查看: https://bitbucket.org/burneraccount/scrollviewexample

git https: https://bitbucket.org/burneraccount/scrollviewexample.git

git ssh: git@bitbucket.org:burneraccount/scrollviewexample.git

^这是一个简洁,独立的Xcode项目,它体现了我在实际工作中遇到的问题.

摘要

我试图实现静态图像效果,其中图像(示例中的摇滚)看起来粘在屏幕上,而较低的内容向上滚动似乎在滚动视图上方.

有一个屏幕大小(UIScrollView*)mainScrollView.这个滚动视图有一个(UIView*)contentView.contentView是~1200点长并有两个子视图:(UIScrollView*)imageScroller和(UITextView*)textView.

一

一切顺利,直到你向上滚动一点,然后快速向下滚动.移动停止后产生的位置不正确.它以某种方式在scrollviewDidScroll委托方法中不能正确更新.快速向下滚动(仅在您向上拖动之后)表现得有些正确,但仍会导致错误放置视图:

二

轻轻拖动几乎没有任何作用,并且滚动的速度与不正确的偏移直接相关.

这是违规代码:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == self.mainScrollView)
    {

        CGFloat mainOffset = self.mainScrollView.contentOffset.y;
        if (mainOffset > 0 && mainOffset < self.initialImageScrollerFrame.size.height)
        {
            CGRect imageFrame = self.imageScroller.frame;
            CGFloat offset = mainOffset-self.lastOffset;
            self.imageScroller.frame = CGRectMake(imageFrame.origin.x,
                                                  imageFrame.origin.y + offset, // scroll up
                                                  imageFrame.size.width,
                                                  imageFrame.size.height - offset); // hide the bottom of the image
            self.lastOffset = mainOffset;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

我几乎以我能想象的每一种方式对其进行了重组,它总是有类似的效果.最糟糕的部分是非常简单直接的代码无法完成看起来像是保证做的事情.同样奇怪的是,我在我的真实项目中使用的缩放效果使用相同的机制来调整相同的视图元素.它在内部(contentOffset < 0)而不是在内部运行(contentOffset > 0),因此它只会在imageScroller您将视图拉到正常偏移下方时放大.这导致我认为有些数据在穿过时会丢失contentOffset 0,但我的阴谋一整天都被击落了.

这个示例比我正在处理的真实项目复杂得多,但它正确地再现了问题.如果您无法打开我的项目或无法连接到回购,请告诉我.

对此可能有一个很明显的解决办法,但我已经过了几个小时,有了新的观点.如果我能让这个工作,我会非常惊讶.

fou*_*dry 2

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == self.mainScrollView)
    {

        CGFloat mainOffset = self.mainScrollView.contentOffset.y;
        if (mainOffset >= 0 && mainOffset < self.initialImageScrollerFrame.size.height)
        {
            CGRect imageFrame = self.imageScroller.frame;
            CGFloat offset = self.mainScrollView.contentOffset.y-self.lastOffset;
            if ( imageFrame.origin.y + offset > 0) {  //[2]
                self.imageScroller.frame = CGRectMake(imageFrame.origin.x,
                                                      imageFrame.origin.y + offset, 
                                                      imageFrame.size.width,
                                                      imageFrame.size.height - offset); 
                self.lastOffset = mainOffset;
            }
        }else if (mainOffset < 0) {  //[1]
            self.imageScroller.frame = self.initialImageScrollerFrame;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

[1] - 当您的mainOffset值低于零时,您需要重置 imageScroller 框架。ScrollViewDidScroll 不会注册每个像素的移动,它只是偶尔被调用(尝试记录它,你会看到)。因此,当您滚动得越快,其偏移量就会越远。这可能会导致正滚动(例如+15)在下次调用scrollViewDiDScroll时变成负滚动。因此,即使您希望它为零,您的 imageScroller.frame.y 也可能会卡在 +15 偏移量上。因此,一旦您检测到 mainOffset 为负值,您就需要重置 imageScroller 框架。

[2] - 类似地,您需要确保您的 imageScroller.frame.y 始终为 +ve。

这些修复可以完成工作,但我仍然认为它们“丑陋且不适合生产”。对于更清晰的方法,您可能需要重新考虑这些视图之间的相互作用以及您想要实现的目标。

顺便说一下,你的“image.png”实际上是一张jpg。虽然这些在模拟器上渲染得很好,但它会在设备上崩溃(出现编译器错误)。