iOS swift UIView及其Subview通过透明度的判
2020-07-16 本文已影响0人
彭磊PL
背景
在开发过程中会有这样一种场景:在一个页面A上弹出了一个透明或者半透明的view B,希望在点击ViewB的透明或者半透明区域的时候,将点击事件透传给下层页面A。废话不说啦,请看代码
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let alpha = alphaOfPoint(point: point)
// 处于当前view及sub view的点击位置颜色的alpha值大于阈值,则事件不穿透,否则就透传
if alpha > DuPoplayerWKWebview.alphaThreshold {
return true
}else {
return false
}
}
func alphaOfPoint(point: CGPoint) -> CGFloat {
return alphaOfPointFromLayer(point: point)
}
func alphaOfPointFromLayer(point: CGPoint) -> CGFloat {
var pixel = [UInt8](repeatElement(0, count: 4))
// var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
context?.setBlendMode(.copy)
context?.translateBy(x: -point.x, y: -point.y)
if let context = context {
layer.render(in: context)
}
let alpha = CGFloat(pixel[3]) / CGFloat(255.0)
return alpha
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.point(inside: point, with: event) {
return super.hitTest(point, with: event)
}
guard isUserInteractionEnabled, !isHidden, alpha > 0 else {
return nil
}
for subview in subviews.reversed() {
let convertedPoint = subview.convert(point, from: self)
if let hitView = subview.hitTest(convertedPoint, with: event) {
return hitView
}
}
return nil
}
hitTest:withEvent:方法大致处理流程是这样的:
- 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
- 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
- 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕。
最后附上Demo