UIScrollView中的UIScrollView,如何在两者之间滚动时保持平滑过渡 [英] UIScrollView within a UIScrollView, how to keep a smooth transition when scrolling between the two

查看:103
本文介绍了UIScrollView中的UIScrollView,如何在两者之间滚动时保持平滑过渡的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following layout (see below), which for most circumstances works just fine. The user is able to scroll within the blue UIScrollView (which for all intents and purposes is a UITableView, but this question generalises this), and then when they've reached the end of this scroll view, they can start scrolling again (they have to take their finger off, and on again, because the inner scroll view rubberbands otherwise), and the 'super' scroll view starts scrolling, revealing the rest of the image.

这是整个(他们必须关闭他们的手指,再次开启,因为内部滚动查看橡皮筋否则)我不想要。理想情况下,一旦包含的 UIScrollView 到达其内容的末尾,我希望superview直接接管滚动,以便内部滚动视图不会橡皮带。

It's the whole (they have to take their finger off, and on again, because the inner scroll view rubberbands otherwise) that I don't want. Ideally, once the contained UIScrollView reaches the end of its content, I want the superview to take over scrolling straight away, so that the inner scroll view doesn't rubberband.

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

The same goes when the user is scrolling back up; when the red scrollview reaches the top of it's content, I want the inner blue scroll view to start scrolling up straight away, instead of the red scroll view rubberbanding at the top.

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

Any idea how? I am able to determine when the scroll views have reached the ends of their content, but I'm not sure how to apply this knowledge to achieve the effect I'm after. Thanks.

// 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) { ... }


推荐答案

是的。我有一个漂亮的技巧。

Yeah. Ive got a nifty trick for you.

滚动视图不是让你的红色轮廓视图使其成为填充屏幕的普通UIView。在该视图中,您可以在插图中布置滚动视图(表格视图)和图像视图。

Instead of having your red outlined view a scrollview make it a normal UIView that fills the screen. In that view lay out your scroll view (table view) and image view as they are in your illustration.

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

Place a scrollview that fills the bounds of the root view (i.e. also fills the screen) above all the other scrollview and image views. Set the content size of this view to be the total content height of all the views you want to scroll through. In otherwords there is an invisible scrollview sitting on top of all your other views and its content size height is inner scrollview (tableview) content size height + image view size height.

层次结构应如下所示:

然后,使用非常高的内容大小制作的顶部滚动视图使其委托成为您的视图控制器。实现 scrollViewDidScroll ,我们将会有一些魔力。

Then this scrollview on top that you have made with the really tall content size make its delegate be your view controller. Implement scrollViewDidScroll and we'll work some magic.

Scrollviews基本上通过调整边界原点来滚动时髦公式势头和东西。因此,在我们的 scrollviewDidScroll 方法中,我们只需调整基础视图的边界:

Scrollviews basically scroll by adjusting the bounds origin with funky formulas for momentum and stuff. So in our scrollviewDidScroll method we will simply adjust the bounds of the underlying views:

-(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;
}

你会发现,当这个人造滚动的每一帧动画都调用scrollViewDidScroll所包含的视图看起来很自然。

You will find that as scrollViewDidScroll is called every frame of animation that this faux scrolling of the contained views looks really natural.

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

But wait! I hear you say. That scroll view on top now intercepts ALL touches, and the views underneath it need to be touched as well. I have an interesting solution for that as well.

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

Set the scrollview on top to be off screen somewhere (i.e. set its frame off screen, but still the same size.) and then in your viewDidLoad method you add the scrollview's panGestureRecogniser to the main view. This will mean that you get all the iOS natural scrolling momentum and stuff without actually having the view on the screen. The contained scroll view will now probably go juddery as its pan gesture recognizer will get called as well (they work differently to UIEvent handling) so you will need to remove it.

- (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
}

我很乐意制作这个,所以这是一个关于github示例项目的链接:
https:// github.com/joelparsons/multipleScrollers

I had fun making this so heres a link to the sample project on github: https://github.com/joelparsons/multipleScrollers

编辑:

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

To show the scrollbar for the top scrollview when its off the screen no matter where you put it you can set the scrollIndicatorInsets to an inset created like this:

CGPoint scrollviewOrigin = self.scrollview.frame.origin;
self.scrollview.scrollIndicatorInsets = UIEdgeInsetsMake(-scrollviewOrigin.y,0,scrollviewOrigin.y,scrollviewOrigin.x);

*请注意,scrollview仍然必须是正确的高度,但我相信你明白这个想法。

*caveat that the scrollview still has to be the right height but I'm sure you get the idea.

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

And then to make the bar draw outside the scrollview's visible bounds you have to turn off clips to bounds

self.scrollview.clipsToBounds = NO;

这篇关于UIScrollView中的UIScrollView,如何在两者之间滚动时保持平滑过渡的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆