如何点击topView时获取其相对bottomView的位置并屏蔽bottomView触摸
解决方案
1. 先让bottomView不响应触摸
直接禁用bottomView的交互能力,这样触摸事件会自动穿透到上层的topViews,不会被bottomView拦截:
bottomView.isUserInteractionEnabled = false
小提示:如果你的视图层级里bottomView是mainView(包含topViews)的父视图,这个设置依然有效,触摸会正常传递到mainView里的topViews。
2. 给每个topView单独绑定触摸事件(替代在bottomView里用touchesBegan)
不要在bottomView里处理触摸逻辑,直接给每个topView添加触摸识别,这样能精准定位到被点击的那个topView,再去做坐标系转换:
方法一:用UITapGestureRecognizer实现
在创建topViews的循环里,给每个视图加上点击手势:
for topView in topViews { topView.isUserInteractionEnabled = true // 确保topView能接收触摸 let tap = UITapGestureRecognizer(target: self, action: #selector(onTopViewTapped(_:))) topView.addGestureRecognizer(tap) }
然后实现触摸处理的方法:
@objc private func onTopViewTapped(_ gesture: UITapGestureRecognizer) { guard let tappedTopView = gesture.view else { return } // 3. 核心:把topView的位置转换到bottomView的坐标系里 // 示例1:获取topView的中心点在bottomView中的坐标 let topViewCenterInBottom = tappedTopView.convert(tappedTopView.center, to: bottomView) // 示例2:获取topView整个frame在bottomView中的矩形范围 let topViewFrameInBottom = tappedTopView.convert(tappedTopView.bounds, to: bottomView) // 这里就可以用转换后的位置创建你的贝塞尔路径了 drawBezierPath(from: topViewCenterInBottom, to: yourEndPoint) }
方法二:自定义TopView重写触摸方法
如果你有自定义的TopView类,也可以直接在类里重写触摸逻辑,通过闭包或代理把位置传出来:
class TopView: UIView { var onTap: ((CGPoint) -> Void)? override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 根据你的视图层级调整bottomView的获取方式,这里假设bottomView是mainView的父视图 if let bottomView = self.superview?.superview { let centerInBottom = self.convert(self.center, to: bottomView) onTap?(centerInBottom) } } }
创建topView时绑定回调:
let topView = TopView() topView.onTap = { [weak self] centerPoint in guard let self = self else { return } self.drawBezierPath(from: centerPoint, to: self.yourEndPoint) }
3. 坐标系转换的核心逻辑
UIKit的convert(_:to:)方法是关键,它能把某个点/矩形从当前视图的坐标系,直接转换到目标视图的坐标系里。如果需要反向转换(比如把bottomView里的点转到topView),可以用convert(_:from:)。
如果需要获取触摸点在topView内的位置,再转成bottomView的坐标,也可以这么写:
if let touch = touches.first { let touchPointInTopView = touch.location(in: tappedTopView) let touchPointInBottomView = tappedTopView.convert(touchPointInTopView, to: bottomView) }
为什么之前的方式不行?
你在bottomView的touchesBegan里只能拿到触摸点相对于bottomView的位置,但无法直接关联到是哪个topView被点击了。而直接给topView绑定触摸事件,既能明确知道触发触摸的视图,又能通过坐标系转换精准拿到相对bottomView的位置,完全匹配你的需求。
内容的提问来源于stack exchange,提问作者Osama Naeem
相关产品推荐
相关产品推荐

