IOS面试题(UIView) ----- 事件传递机制 - 简书
iOS 事件传递面试题_ios 时间传递的面试题-CSDN博客
面试题1:
iOS页面上有一个UIbutton a,有点击事件afunc;上层有个全屏的视图 B,有点击事件bfunc;正常点击a,响应的是B。怎么才能让B不响应,A响应?
-
事件传递:
如果全屏视图B是一个普通视图(非按钮等控件),你可以在它的视图控制器中复写touchesBegan(_:with:)
、touchesMoved(_:with:)
、touchesEnded(_:with:)
和touchesCancelled(_:with:)
方法,并在这些方法中对触摸位置进行检查。如果触摸位置在UIButton a的范围内,你可以将事件直接传递给UIButton a。 -
重写全屏视图B的
point(inside:with:)
方法:
通过调整视图层级,确保UIButton a在视图层次中位于全屏视图B之上。这样,点击事件自然会首先传递给UIButton a。可以通过调用bringSubviewToFront(_:)
方法来确保UIButton a位于最前面:class FullscreenView: UIView { weak var buttonA: UIButton? override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { // 检查触摸点是否在buttonA内部 if let buttonA = buttonA, buttonA.frame.contains(point) { // 如果在buttonA内,返回false以允许buttonA响应事件 return false } // 否则,返回true以允许全屏视图B响应事件 return true } }
-
使用手势识别器:
方式一:在这个方案中,我们实现了
UIGestureRecognizerDelegate
的gestureRecognizer(_:shouldReceive:)
方法,以便在触摸发生在UIButton a上时返回false
,这样全屏视图B上的手势识别器就不会接收到这个触摸事件。以上是实现特定区域事件穿透的几种方案。你可以根据具体的应用场景和需求,选择最适合你的方法。
class ViewController: UIViewController, UIGestureRecognizerDelegate { @IBOutlet var buttonA: UIButton! @IBOutlet var fullscreenView: UIView! override func viewDidLoad() { super.viewDidLoad() let tapGesture = UITapGestureRecognizer(target: self, action: #selector(bFunc)) tapGesture.delegate = self fullscreenView.addGestureRecognizer(tapGesture) } @objc func aFunc(sender: UIButton) { // 处理buttonA点击事件 } @objc func bFunc(gesture: UITapGestureRecognizer) { // 处理全屏视图B点击事件 } // UIGestureRecognizerDelegate方法 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if touch.view == buttonA { // 如果触摸的视图是buttonA,不让全屏视图B的手势识别器接收这个触摸事件 return false } return true } }
方式二:为全屏视画B添加一个UITapGestureRecognizer,并在其回调方法中检查触摸点是否在UIButton a的边界内。如果是,则不执行bfunc,反之则执行bfunc。示例代码如下:
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:))) B.addGestureRecognizer(tapRecognizer) @objc func viewTapped(_ recognizer: UITapGestureRecognizer) { let location = recognizer.location(in: B) if a.frame.contains(location) { // 触摸点在UIButton a内,你可以在这里调用afunc() } else { // 触摸点不在UIButton a内,执行bfunc() bfunc() } }
-
条件性地拦截事件:
如果你不能改变视图层级,并且需要更细致地控