You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何点击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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:47:27