事件穿透

在事件响应和传递这篇文章中,讲了iOS中的事件响应和传递,今天在做项目的时候,正好碰到了一个应用的场景,因此记录下来。

需求

首页头部需要添加这样一个视图


image.png

点击左右两个按钮,底部的滑块跟着滑动,同时也可以拖动滑块到选中的按钮位置。

思路和问题

看到这个设计图一开始的想法就是,左右两个按钮,底部一个滑块视图,然后到做的时候,发现如果要做手势拖拽的话,那么由于层级关系,滑块肯定是在两个按钮下面的,如果要触发滑动手势,势必会被按钮的点击事件阻止。


image.png

通过重写hitTest方法解决

首先判断点击点是位于左侧按钮区域还是右侧按钮区域,在根据按钮的选中状态来判断。
初始状态时左侧按钮选中,右侧没选中,同时滑块位于左侧。
如果触摸点在右侧按钮区域,此时应该走的流程是响应右侧按钮事件。
如果触摸点在左侧区域,此时左侧区域是选中状态,应该响应的是滑块的拖动事件。
依照这个思路,就有了下面的这段代码

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let superHitPoint = self.convert(point, to: self.superview)
    if superHitPoint.x <= self.frame.width {
        if self.frame.minX > 0 {    // 点击左侧按钮,但是现在响应的是右侧按钮,原样传递上去
            return super.hitTest(point, with: event)
        }
        if self.isSelected {
            return strikeView
        } else {
            return super.hitTest(point, with: event)
        }
    } else {
        if self.frame.minX == 0 {     // 同理
            return super.hitTest(point, with: event)
        }
        if self.isSelected {
            return strikeView
        } else {
            return super.hitTest(point, with: event)
        }
    }
}

这里要注意的一点是,由于事件响应链是系统会从后往前遍历子视图,我们点击任何一个区域,两个按钮都会响应hitTest方法,在判断触摸点的区域之后,还要判断一下当期响应的按钮是不是我们期望的按钮,如果不是,则不作任何改动。

你可能感兴趣的:(事件穿透)