加载遮罩用带透明度UIView时点击事件穿透至底层按钮的问题
解决半透明遮罩UIView点击穿透底层按钮的问题
这个问题我之前也碰到过,本质是iOS的触摸事件传递机制在起作用:你的半透明遮罩虽然视觉上覆盖了全屏,但因为它没有处理触摸事件,系统会把触摸继续向下传递给底层的可交互控件(比如你的按钮)。
下面给你两种简单可行的解决方法,选哪种都能解决问题:
方法1:自定义遮罩视图拦截触摸
创建一个UIView的子类,重写hitTest(_:with:)方法让它直接返回自身,这样所有落在遮罩上的触摸都会被拦截,不会传递到底层视图:
class LoadingMaskView: UIView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 强制拦截所有触摸事件,阻止向下传递 return self } }
然后把你原来的UIView替换成这个自定义类就行:
let loadingView = LoadingMaskView() loadingView.tag = 9999 loadingView.frame = UIScreen.main.bounds // 简化写法,直接用屏幕边界 loadingView.backgroundColor = UIColor.white.withAlphaComponent(0.4) controller.view.addSubview(loadingView)
方法2:添加空点击手势(无需自定义类)
如果不想自定义子类,也可以给遮罩视图加一个空的点击手势识别器——系统会认为遮罩已经处理了触摸事件,就不会再把事件向下传递了:
let loadingView = UIView() loadingView.tag = 9999 loadingView.frame = UIScreen.main.bounds loadingView.backgroundColor = UIColor.white.withAlphaComponent(0.4) // 添加空的点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(emptyMaskTapHandler)) loadingView.addGestureRecognizer(tapGesture) controller.view.addSubview(loadingView) // 实现空的处理方法 @objc private func emptyMaskTapHandler() { // 什么都不用做,只是用来拦截触摸事件 }
补充说明
为什么原来的遮罩会穿透?因为默认情况下,UIView如果没有绑定任何触摸事件处理(比如手势、重写触摸方法),系统会判定它不需要处理触摸,于是就把事件继续传递给下层能处理的视图。通过上面两种方法,我们相当于告诉系统“这个遮罩要接管触摸”,自然就能阻止事件穿透了。
内容的提问来源于stack exchange,提问作者r_honey
相关产品推荐
相关产品推荐

