iOS 多个scrollview联动(附DEMO)

作者: 波儿菜 | 来源:发表于2017-05-27 23:14 被阅读1384次

    前言

    在移动应用实际开发过程中,往往会有多个scrollview嵌套的界面需求,这种需求已经司空见惯,解决方案也多种多样,这里就介绍一下我认为最优的解决方案。

    效果图:

    Untitled.gif

    结构解读:

    底层有一个UIScrollview子类,这里叫它mainScrollview;
    mainScrollview下方嵌套了两个视图(通常这两个视图也用UIScrollview子类来处理,这里叫它moduleScrollview)。
    毫无疑问,我们通常的做法是在mainScrollview的下方先嵌套一个横向滚动的UIScrollview子类,再在这个横向滚动的视图上嵌套n个子模块(像gif中的“图文详情”和“客户评分”两个子模块)。
    这点我不做过多解释,结构的搭建争议不大,重点在交互上。

    尝试过的思路:

    有一种思路总结起来是,通过开启或者禁止mainScrollview和moduleScrollview的交互来达到何时响应某个scrollview的目的。在手指拖动的临界状态,通过大量的判断逻辑来主动控制某些scrollview的偏移量,进而达到“欺骗观众”的响应拖动状态。
    缺点:逻辑复杂程度过大,容错处理很多,致命的缺陷是临界状态无法实现scrollview的减速效果(惯性效果),当然有的开发者会说利用核心动画能实现这一效果,但是,我认为这就太费周折了。

    最佳方案:

    首先我们来了解一个UIGestureRecognizerDelegate协议拟定的方法:

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
    

    这个方法的作用大致可以理解为是否允许手势穿透。在iOS开发中,相同的手势,响应者往往是最上层的视图,所以重写这个方法返回为YES就可以让下层的视图响应同样的手势。
    值得注意的是,UIScrollview实现了这个协议的方法,所以,我们可以让子模块直接继承UIScrollview(或其子类),然后重写该方法。
    如此一来,我们需要做的,仅仅是判断何时不让某个scrollview改变偏移量即可。
    优点:实现简单,丝滑无卡顿

    核心思想:让moduleScrollview 和mainScrollview 同时响应上拉或者下拉手势,只需判断何时不允许某个scrollview改变contentOffset

    DEMO

    DEMO见github地址:https://github.com/indulgeIn/YBMultistageScrollView

    注意:DEMO中嵌套进了UIWebview,并简单做了逻辑处理方案,在iOS8系统以上的情况,还是建议大家将UIWebview更换为WKWebview,性能和兼容性的提升不容小觑。

    相关文章

      网友评论

      • 小马哥nice:大神,请问那个 图文详情 客户评分的tab选项下面的分隔线怎么去掉?
        波儿菜:@小马哥nice 这里只是提供了一个嵌套交互的方案
        波儿菜:@小马哥nice 你问的这些基础业务问题自己解决哈
      • 葫芦闲人:很牛逼,解决了我的问题
      • 幻想无极:这个东西坑也多,已经感受过了
        幻想无极:@幻想无极 而且开了这个就相当于开了多点触碰
        波儿菜:@幻想无极 是啊 不过思路是一样的
        幻想无极:@幻想无极 实际项目遇到复杂的需求还是要踩坑
      • 梵高的老巫婆:求助 我看了你在scrollview上加的是tableview 我在scrollview上加的是控制器的view 穿透效果一直不行,(手势穿透方法我写在控制器里面了) 跟这个有关系吗?
        波儿菜:@梵高的老巫婆 控制器之间的交互穿透我没尝试过,需要去研究响应链相关的知识。所以建议你还是使用scrollview好点。。
      • 行走的菜谱:在if (self.levelListView.selectedIndex == 0 && _picAndTextTableView.offsetType == OffsetTypeCenter) {
        scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, scrollView.contentSize.height-scrollView.H);
        }

        if (self.levelListView.selectedIndex == 1 && _evaluateTableView.offsetType == OffsetTypeCenter) {
        scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, scrollView.contentSize.height-scrollView.H);
        }
        这里设置外层scrollview的偏移的时候,怎么会循环的调用scrollview的scrollViewDidScroll方法,楼主可以帮忙看下吗
      • LV大树:你的穿透demo能不能发一下呢
        波儿菜:@FiredPeter 有地址嘛
      • LV大树:我正要仿滴滴首页。。。。看看这个思路行不行。
        LV大树:https://segmentfault.com/q/1010000013915226?_ea=3500499
      • e8b6cbadf7fb:楼主的思路很棒,正好项目用到了,表示感谢😝,在调试的时候发现有两个地方可以进步优化一下:
        1、在最外层的界面的scrollViewDidScroll中,scrollView.contentSize.height-H-0.5这一块再多减去scrollView.contentInset.top
        2、还是这个方法中遍历一下全部子Table,如果已经被拉到了屏幕中间,将其他子table的contentOffset全部置为Zero
        if (idx != self.selectedIndex && self.offsetType != OffsetTypeMax) {
        obj.contentOffset = CGPointZero;
        }
        波儿菜:@意林 嗯嗯 可以的
      • PGOne爱吃饺子:楼主 可以加个QQ号么,问你一个问题,谢谢
        波儿菜:1106355439
      • 492647699e8d:然而你这个 在垂直方向上 并不能连续滚动
        波儿菜:@如此简单 我查看了一下,在内嵌web的时候,web里面的拖动手势阻止了响应下传,这个问题我暂时不知道如何解决
        492647699e8d:你有联系方式么? 加一下呗 我QQ 432591 交流一下
        波儿菜:@如此简单 可以的呀
      • 不会算卦的杨大仙:...大侠这个有个问题啊 如果左右滑动的时候上下也在滑 会感觉很怪异
        不会算卦的杨大仙:@indulge_in 大佬 这个解决方案是不是意味着不能在下面每个table加自己的刷新控件啊
        不会算卦的杨大仙:@indulge_in 6666这么迅速 我去更新下 蟹蟹
        波儿菜:@不会算卦的杨大仙 嗯,解决方法就是在左右滚动开始拖动时禁止子列表的滚动,结束拖动时打开子列表滚动。 具体的我已经修改提交了github了。:blush:
      • Hengry:正解,我也是用这种方法解决嵌套手势冲突问题
        Hengry:@indulge_in 高手所为😆
        波儿菜:@DevHank :smile:这种方式简单高效

      本文标题:iOS 多个scrollview联动(附DEMO)

      本文链接:https://www.haomeiwen.com/subject/uxmexxtx.html