好的,我有一个巧妙的技巧可以和你分享。
不要使用一个带有红色边框的滚动视图,而是把它作为一个填充整个屏幕的普通UIView。在该视图中,按照你的示例布置滚动视图(表视图)和图像视图。
在所有其他滚动视图和图像视图上方放置一个填充根视图(即也填充整个屏幕)的滚动视图。将此视图的内容大小设置为您想要滚动的所有视图的总内容高度。换句话说,有一个无形的滚动视图位于所有其他视图的顶部,其内容大小高度为内部滚动视图(表视图)内容大小高度+图像视图大小高度。
层次结构应该如下所示:
然后,在你创建的这个具有非常高内容大小的顶部滚动视图上,将其代理设置为你的视图控制器。实现scrollViewDidScroll
,我们将进行一些魔法。
滚动视图基本上通过调整边界原点的奇妙公式来滚动,以产生动量等效果。因此,在我们的scrollviewDidScroll
方法中,我们将简单地调整基础视图的边界:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat maxYOffsetForUnderScrollView = self.underScrollView.contentSize.height - self.underScrollView.bounds.size.height;
CGRect scrolledBoundsForContainerView = self.view.bounds;
if (scrollView.contentOffset.y <= maxYOffsetForUnderScrollView) {
self.containerView.bounds = scrolledBoundsForContainerView;
self.underScrollview.contentOffset = scrollView.contentOffset;
return;
}
self.underScrollView.contentOffset = CGPointMake(0, maxYOffsetForUnderScrollView);
scrolledBoundsForContainerView.origin.y = scrollView.contentOffset.y - maxYOffsetForUnderScrollView;
self.containerView.bounds = scrolledBoundsForContainerView;
}
你会发现,由于 scrollViewDidScroll 在每一帧动画中被调用,所以这种包含视图的虚拟滚动看起来非常自然。
但是等等!我听到你说。现在顶部的滚动视图截取了所有的触摸事件,而其下面的视图也需要被触摸到。我有一个有趣的解决方案。
将位于顶部的滚动视图设置为在屏幕之外(即将其框架设置为在屏幕之外,但仍然具有相同的大小)。然后在你的 viewDidLoad 方法中,将该滚动视图的 panGestureRecogniser 添加到主视图中。这意味着您将获得所有 iOS 的自然滚动动量和其他东西,而不必实际将该视图显示在屏幕上。由于它们的工作方式与 UIEvent 处理不同,因此包含的滚动视图现在可能会出现抖动,因此您需要将其移除。
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer:self.scrollview.panGestureRecognizer];
[self.underScrollview removeGestureRecognizer:self.underScrollView.panGestureRecognizer];
}
我很享受制作这个东西,所以这里有一个指向Github上示例项目的链接:https://github.com/joelparsons/multipleScrollers
编辑:
如果想要在顶部滚动视图离屏幕时显示滚动条,可以将scrollIndicatorInsets
设置为此样式的插入物:
CGPoint scrollviewOrigin = self.scrollview.frame.origin;
self.scrollview.scrollIndicatorInsets = UIEdgeInsetsMake(-scrollviewOrigin.y,0,scrollviewOrigin.y,scrollviewOrigin.x);
需要注意的是,仍然必须具有正确的高度,但我相信你明白这个意思。
接下来,为了使工具栏绘制在可见范围之外,您必须关闭剪切边界功能。
self.scrollview.clipsToBounds = NO;