首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么clipsToBounds会阻止子视图被触摸?

为什么clipsToBounds会阻止子视图被触摸?
EN

Stack Overflow用户
提问于 2020-12-05 20:56:24
回答 1查看 343关注 0票数 1

假设您有一个superview,它的大小比它的子视图要小。将superview的clipsToBound属性设置为false。如果您点击超出superview界限的子视图的突出区域,为什么命中测试返回零?

我的理解是,命中测试从子视图开始,一直工作到superview。那么,为什么要测试的superview的属性比子视图还要晚呢?或者,命中测试是否从根开始到树视图,如视图控制器->、主视图->子视图?

我从here中找到了一个定制的点击测试,它允许你点击超级视图界限之外的子视图区域,但我不知道为什么要改变子视图的顺序(它有效,我只是不知道为什么)。我的例子甚至只有一个子视图。

代码语言:javascript
复制
class ViewController: UIViewController {
    let superview = CustomSuperview(frame: CGRect(origin: .zero, size: .init(width: 100, height: 100)))
    let subview = UIView(frame: CGRect(origin: .zero, size: .init(width: 200, height: 200)))

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.superview)
        self.superview.backgroundColor = .red
        self.superview.clipsToBounds = false
        
        self.superview.addSubview(self.subview)
        self.subview.backgroundColor = .blue
         
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapped))
        self.subview.addGestureRecognizer(tap)
    }
    
    @objc func tapped(_ sender: UIGestureRecognizer) {
        print("tapped")
    }
}

class CustomSuperview: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        if clipsToBounds || isHidden || alpha == 0 {
            return nil
        }

        for subview in subviews.reversed() {
            let subPoint = subview.convert(point, from: self)
            if let result = subview.hitTest(subPoint, with: event) {
                return result
            }
        }

        return nil
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-05 21:58:46

,我的理解是,命中测试从子视图开始,一直工作到超级视图。

那么你的理解是完全错误的。我们来解决这个问题。首先,让我们澄清其他一些误解:

  • reversed是一种完全的红鲱鱼,与之无关。子视图总是按反向顺序进行测试,因为前面的子视图需要优先于后面的子视图。

  • clipsToBounds也是一种完全红色的鲱鱼。它所做的就是更改是否可以在其superview之外看到子视图;它对您是否可以触摸其superview之外的子视图没有任何影响。

好吧,那这是怎么回事?让我们以包含子视图A的视图V为例,假设A在V之外。假设你可以看到A,然后点击A。

现在点击测试开始了。但事情是这样的:它从窗口的级别开始,然后沿着视图层次结构工作。因此,窗口从询问其子视图开始;只有一个视图控制器的主视图。

因此,现在我们进行递归,视图控制器的主视图询问它的子视图。其中之一是V。“嘿,V,你体内有水龙头吗?”“不!”(你必须同意,这是正确的答案,因为我们已经说过A在V.之外)

所以视图控制器的主视图放弃了V,从来没有发现点击是在A上,因为我们从来没有递归过那么远。所以它向上报告:“水龙头没有出现在我的任何子视图上,所以我必须报告水龙头是在我身上的。”水龙头已经通到视图控制器的主视图。

但是您可以通过重写hitTest的实现来改变这种行为。

代码语言:javascript
复制
override func hitTest(_ point: CGPoint, with e: UIEvent?) -> UIView? {
    if let result = super.hitTest(point, with:e) {
        return result
    }
    for sub in self.subviews.reversed() {
        let pt = self.convert(point, to:sub)
        if let result = sub.hitTest(pt, with:e) {
            return result
        }
    }
    return nil
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65161861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档