UIScrollView中的UIScrollView,如何在两者之间滚动时保持平滑过渡

WDU*_*DUK 4 objective-c uitableview uiscrollview ios

我有以下布局(见下文),在大多数情况下工作得很好.用户可以在蓝色内滚动UIScrollView(这是为了所有意图和目的UITableView,但这个问题概括了这一点),然后当他们到达滚动视图的末尾时,他们可以再次开始滚动(他们必须采取他们的手指关闭,再次,因为内部滚动视图橡皮筋否则),"超级"滚动视图开始滚动,显示图像的其余部分.

它是整体(他们必须脱掉他们的手指,再次,因为内部滚动视图橡皮筋否则),我不想要.理想情况下,一旦包含UIScrollView到达其内容的末尾,我希望superview直接接管滚动,以便内部滚动视图不是橡皮带.

当用户向上滚动时也是如此; 当红色滚动视图到达其内容的顶部时,我希望内部蓝色滚动视图开始直接向上滚动,而不是顶部的红色滚动视图橡皮筋.

屏幕布局;  UIScrollView中的UIScrollView + UIImageView

知道怎么样?我能够确定滚动视图何时到达其内容的末尾,但我不确定如何应用这些知识来实现​​我所追求的效果.谢谢.

// Inner (blue) scroll view bounds checking
if (scrollView.contentOffset.y + scrollView.frame.size.height > scrollView.contentSize.height) { ... }

// Outer (red) scroll view bounds checking
if (scrollView.contentOffset.y < 0) { ... }
Run Code Online (Sandbox Code Playgroud)

jac*_*ash 14

是啊.我有一个漂亮的技巧给你.

而不是让您的红色轮廓视图滚动视图使其成为填充屏幕的正常UIView.在该视图中,您可以在插图中显示滚动视图(表格视图)和图像视图.

在所有其他滚动视图和图像视图上方放置一个滚动视图,该视图填充根视图的边界(即也填充屏幕).将此视图的内容大小设置为要滚动的所有视图的总内容高度.换句话说,在所有其他视图的顶部有一个不可见的scrollview,其内容大小高度为内部scrollview(tableview)内容大小高度+图像视图大小高度.

层次结构应如下所示:

在此输入图像描述

然后,您使用非常高的内容大小创建的顶部滚动视图使其委托成为您的视图控制器.实施scrollViewDidScroll,我们将工作一些魔术.

Scrollviews基本上是通过调整边界原点来调整动态和东西的时髦公式.所以在我们的scrollviewDidScroll方法中,我们将简单地调整底层视图的边界:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

    //the scroll view underneath (in the container view) will have a max content offset equal to the content height
    //but minus the bounds height
    CGFloat maxYOffsetForUnderScrollView = self.underScrollView.contentSize.height - self.underScrollView.bounds.size.height;

    CGRect scrolledBoundsForContainerView = self.view.bounds;

    if (scrollView.contentOffset.y <= maxYOffsetForUnderScrollView) {
        //in this scenario we are still within the content for the underScrollView
        //so we make sure the container view is scrolled to the top and set the offset for the contained scrollview
        self.containerView.bounds = scrolledBoundsForContainerView;
        self.underScrollview.contentOffset = scrollView.contentOffset;
        return;
    }

    //in this scenario we have scrolled throug the entirety of the contained scrollview
    //set its offset to the max and change the bounds of the container view to scroll everything else.
    self.underScrollView.contentOffset = CGPointMake(0, maxYOffsetForUnderScrollView);

    scrolledBoundsForContainerView.origin.y = scrollView.contentOffset.y - maxYOffsetForUnderScrollView;
    self.containerView.bounds = scrolledBoundsForContainerView;
}
Run Code Online (Sandbox Code Playgroud)

你会发现,当每个动画帧调用scrollViewDidScroll时,所包含视图的这种虚假滚动看起来非常自然.

可是等等!我听你说.顶部的滚动视图现在拦截所有触摸,并且还需要触摸它下面的视图.我也有一个有趣的解决方案.

将顶部的滚动视图设置为屏幕某处(即将其框架设置为屏幕外,但仍然保持相同的大小.)然后在您的viewDidLoad方法中将滚动panGestureRecogniser视图添加到主视图中.这意味着您可以获得所有iOS自然滚动动力和内容,而无需在屏幕上实际显示视图.包含的滚动视图现在可能会抖动,因为它的平移手势识别器也会被调用(它们与UIEvent处理的工作方式不同),因此您需要将其删除.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self.view addGestureRecognizer:self.scrollview.panGestureRecognizer];

    [self.underScrollview removeGestureRecognizer:self.underScrollView.panGestureRecognizer];

    //further code to set up content sizes and stuff
}
Run Code Online (Sandbox Code Playgroud)

我玩得很开心所以这是一个链接到github上的示例项目:https: //github.com/joelparsons/multipleScrollers

编辑:

要显示顶部滚动视图的滚动条,当它离开屏幕时无论你放在哪里,你都可以设置为scrollIndicatorInsets这样创建的插图:

CGPoint scrollviewOrigin = self.scrollview.frame.origin;
self.scrollview.scrollIndicatorInsets = UIEdgeInsetsMake(-scrollviewOrigin.y,0,scrollviewOrigin.y,scrollviewOrigin.x);
Run Code Online (Sandbox Code Playgroud)

*请注意,scrollview仍然必须是正确的高度,但我相信你明白了.

然后要在滚动视图的可见边界外绘制条形图,您必须关闭剪辑到边界

self.scrollview.clipsToBounds = NO;
Run Code Online (Sandbox Code Playgroud)