专栏首页王大锤UIScrollView嵌套的完美解决方案

UIScrollView嵌套的完美解决方案

UIScrollView嵌套的完美解决方案

做iOS开发,不可避免的会遇到UIScrollView的嵌套问题,之前也曾遇到过,吭哧吭哧做完了,效果不理想,和产品大战好几回合,就那样了。不可避免的,又一次遇到了这个问题,就和同事一起研究了一下,彻底解决了这个问题。写了一个demo,以后再遇到就直接用了。今天主要是总结一下实现难点。免得自己过段时间又忘了,也给有同样困扰的你一个思路。

需求

如图:

要求:上滑的时候先滑headerView,headerView滑出屏幕时,tableView吸顶且开始滑动。下滑时先滑tableView,滑到顶部第一个cell出现,则开始滑headerView。 这是一个最简单的scrollView嵌套需求,后面还会有进阶的需求。

具体方案

其实嵌套最大的问题就是手势冲突问题,上层的ScrollView会拦截手势,导致手指在上层ScrollView滑动的时候,下层ScrollView不动。所以我们首先要让手势冲突时,两个手势都去响应。这样,我们滑动的时候,两个scrollView都会滑动。

第一步 上层scrollView不拦截手势

extension TopScrollView: UIGestureRecognizerDelegate {
    //手势冲突的时候同时响应
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

第二步 创建上下文对象

上下两层scrollView滑动时候都需要对方的offset来计算,所以我们创建一个上下文对象,让两个scrollView都持有,避免了频繁正反向传值的问题。

class SyncScrollContext {
    var maxOffsetY: CGFloat = 0 //上层最大的滑动距离
    var outerOffset: CGPoint = CGPoint.zero //上层offset
    var innerOffset: CGPoint = CGPoint.zero //下层offset
}

第三步 滑动的时候计算滑动优先级

下层scrollView的contentOffset变化时计算: ~~~ class BottomScrollView: UIScrollView {

class BottomScrollView: UIScrollView {

    var syncScrollContext: SyncScrollContext?
    
    override var contentOffset: CGPoint {
        didSet {
            if contentOffset.y != oldValue.y {
                //下层scrollView滑动
                if syncScrollContext.innerOffset.y > 0 {
                    // 上层的scrollView滑动,则下层的scrollView保持最大滑动距离
                    contentOffset.y = syncScrollContext.maxOffsetY
                } else {
                    //否则,上层不动,下层滑动
                }
                //同步offset到上下文
                syncScrollContext.outerOffset = contentOffset
            }
        }
    }
 }

上层的scrollView的contentOffset变化时计算:

class TopScrollView: UITableView {
    
    var syncScrollContext: SyncScrollContext?
    
    override var contentOffset: CGPoint {
        didSet {
            if contentOffset.y != oldValue.y {
                //上层滑动
                guard let syncScrollContext = syncScrollContext else { return }
                if syncScrollContext.outerOffset.y < syncScrollContext.maxOffsetY {
                    //下层的offset < 下层可滑动最大值,说明下层还需要滑动,上层不动offset为0
                    contentOffset.y = 0
                }
                //不管怎么样,滑动即同步offset到上下文
                syncScrollContext.innerOffset = contentOffset
            }
        }
    }
}

第四步 两个ScrollView嵌套,并正确设置下层scrollView的contentSize

在下层BottomScrollView里面,添加topScrollView并设置contentSize。下层scrollView的contentSize的高 = headerView.height + topScrollView.height。这样,当下层scrollView滑了y(y = headerView的高度)的时候,下层scrollView滑到底了,这时候c下层scrollView无法滑动,也就不存在手势冲突,上层scrollView自动开始响应,流畅的滑动起来了

topScrollView.frame = CGRect(x: 0, y: offsetY, width: bounds.width, height: bounds.height)

contentSize = CGSize(width: bounds.width, height: topScrollView.frame.maxY)

到这里,就已经大功告成了!demo下载:https://github.com/wangdachui/ScrollViewNested

进阶的需求

上下滑的同时,还要求左右滑:

具体就不多讲了,有兴趣看源码。 demo下载:https://github.com/wangdachui/TabScrollView

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • iOS设置tableViewCell之间的间距(去掉UItableview headerview黏性)

    王大锤
  • swift textView内容显示不全

      意见反馈页面有一行提示文字,包含客服QQ,要求qq可点击。为了实现点击功能,这里的文本没有使用UILabel,而是采用了UITextView,使用textV...

    王大锤
  • iOS8 UICollectionView横向滑动demo

    王大锤
  • Spring Boot 使用 Kotlin Script Template 模板引擎kts 开发web

    在 Spring Framework 5.0 M4 中引入了一个专门的Kotlin支持。

    一个会写诗的程序员
  • 2017上半年离婚大数据!出轨率最高的竟是IT男?!

    最新数据显示,2017上半年全国各级民政部门和婚姻登记机构共依法办理结婚登记558万对,比去年下降7.5%;依法办理离婚登记185.6万对,比去年同期上升10....

    华章科技
  • 爬虫工程师的unidbg入门教程

    unidbg 是一个基于 unicorn 的逆向工具,可以黑盒调用安卓和 iOS 中的 so 文件。unidbg 是一个标准的 java 项目。

    吾爱小白
  • 读Zepto源码之Ajax模块

    Ajax 模块也是经常会用到的模块,Ajax 模块中包含了 jsonp 的现实,和 XMLHttpRequest 的封装。 读 Zepto 源码系列文章已经放到...

    对角另一面
  • 非Spring项目如何注入Mapper

    下面mappers标签下的sql/testMapper.xml同样是在resource目录下,这里不支持通配符,Spring配置支持通配符是因为使用Ant通配符...

    每天学Java
  • Java ThreadLocal深度解析

    神秘的寇先森
  • epoll入门

    epoll用到的所有函数都是在头文件sys/epoll.h中声明的,下面简要说明所用到的数据结构和函数: 所用到的数据结构 typedef union epol...

    李海彬

扫码关注云+社区

领取腾讯云代金券