UIScrollView 页面上滑到屏幕内触发事件

18 篇文章 0 订阅

我们需求是想要实现tableView的 willDisplay 方法,当View出现在屏幕上是,进行埋点,

需要在 scrollViewDidScroll 方法里实现。

1、当时同事提了一个方案,就是每次来这个方法,就去遍历子视图,那些在屏幕内,然后根据与上次的状态对比,可以判断是离开还是刚进入屏幕或者是暂时没变化。

可是因为 scrollViewDidScroll 方法调用特别频繁,然后再在里面做for循环遍历子视图,我遍思考别的可行性方案,于是有了第二种

2、我们的需求是,第一次显示在屏幕内,去埋点,那么我忽略掉离开屏幕的子视图,只往下判断,那两个值去记录最新出现在屏幕上的试图为 bottomWidget,当用户往上滑的时候,判断下一个试图是否在屏幕内,如果在,替换bottomWidget,同时我做了一个距离差,我们的每个子视图的高度至少为 114,那么当滑动偏移量距特别小的时候,也就是用户滑动特别慢的时候,无需过多冗余计算,于是我保存了一个 minOffset = 44,得才以下无需遍历的优化代码:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
      judgementViewIsVisitable(contentOffset: scrollView.contentOffset)
}

func judgementViewIsVisitable(contentOffset: CGPoint) {
        if let lastContentOffsetY = lastContentOffsetY {
            let offsetY = contentOffset.y - lastContentOffsetY
            if abs(offsetY) < minOffset {
                return
            }
            self.lastContentOffsetY = contentOffset.y
            if offsetY < 0 { // 往下滑, 需要替换topWidget 暂时不处理
            } else { // 往上滑,替换 bottomWidget,只处理之前没看过的
                if let index = firstVisibleViewDic.firstIndex(where: { model in
                    model == bottomWidget
                }) {
                    if index == firstVisibleViewDic.count - 1 {
                        return
                    }
                    // 判断下一个
                    handleCurrentModel(model: firstVisibleViewDic[index + 1])
                }
            }
        } else {
            lastContentOffsetY = contentOffset.y
        }
}

func handleCurrentModel(model: VisiableWidgetModel) {
        if model.isVisiable == false {
            if let view = widgetViewDict[model.widgetId] as? UIView, !view.isHidden, view.intersectsOtherView(otherView: canVisitableView) {
                model.isVisiable = true
                bottomWidget = model
                perfomViewCanVisited(model: model)
            } else if let vc = widgetViewDict[model.widgetId] as? UIViewController, vc.view.isHidden, vc.view.intersectsOtherView(otherView: canVisitableView) {
                model.isVisiable = true
                bottomWidget = model
                perfomViewCanVisited(model: model)
            }
        }
    }

func perfomViewCanVisited(model: VisiableWidgetModel) {
        // 处理事件
    }

判断是否在屏幕内的代码如下:

// view and view relationship
public extension UIView {
    enum RectRelationType: Int {
        case intersects
        case contains
    }
    
    func intersectsOtherView(otherView: UIView? = nil) -> Bool {
        return relationToOtherView(otherView: otherView, relationType: .intersects)
    }
    
    func containsOtherView(otherView: UIView? = nil) -> Bool {
        return relationToOtherView(otherView: otherView, relationType: .contains)
    }
    
    private func relationToOtherView(otherView: UIView? = nil, relationType: RectRelationType) -> Bool {
        var window = otherView
        if window == nil {
            if #available(iOS 13.0, *) {
                for windowScene: UIWindowScene in (UIApplication.shared.connectedScenes as? Set)! {
                    window = windowScene.windows.first
                    break
                }
            } else {
                window = UIApplication.shared.keyWindow
            }
        }
        
        let selfRect = self.convert(self.bounds, to: nil)
        if let `window` = window {
            let otherRect = window.convert(window.bounds, to: nil)
            switch relationType {
            case .intersects:
                return selfRect.intersects(otherRect)
            case .contains:
                return selfRect.contains(otherRect)
            }
        }
        return false
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值