addSubview和insertSubview 的区别解析

本文解析了子视图在父视图中的堆叠机制,包括如何使用addSubview及insertSubview进行视图层级控制,帮助理解iOS应用中视图显示的先后顺序。

    子视图是以栈的方式存放的(先进后出)


    每次addsubview时都是在最后面添加,即添加到栈顶

    每次在addsubview前和addsubview后可以用[self.view.subViews count]查看子视图的数量,或者用for(UIView  *view  in  self.view.subViews)遍历数组,你就可以看到的子视图是被添加到哪个位置了。

    另外[self.view addSubView:xx.view]   其实就等于[self.view insertSubView:xx.view atIndex:[self.view.subViews count]];

即在最顶层添加view。

   总之:

    addSubview是一层一层往上加,新加的只能放到最上层
    insertSubView可以控制将view添加到指定的层。


根据您的测试结果,`addSubview` 的调用顺序确实会影响按钮的点击行为。这是因为在 macOS/iOS 的视图层级中,**后添加的子视图会覆盖在先添加的子视图之上**,即使它们的布局约束没有重叠,事件响应也可能受到层级影响。 --- ### **问题原因分析** 1. **视图层级与事件响应** - 当您按以下顺序添加按钮时: ```swift addSubview(testButton) addSubview(bannerButton) addSubview(redBotButton) ``` - `redBotButton` 作为最后添加的视图,会位于视图层级的最顶层。 - 如果 `bannerButton` `redBotButton` 的点击区域(`frame` 或 `hitTest`)存在潜在重叠(即使布局约束未明确重叠),系统可能会将事件优先传递给 `redBotButton`,导致 `bannerButton` 无法响应点击。 2. **SnapKit 约束的潜在问题** - 虽然您的约束看起来是独立的(如 `centerX` 分别对齐 `bannerView` `redBotView`),但如果父视图的 `clipsToBounds` 为 `false` 或视图边界计算异常,可能导致事件穿透。 --- ### **解决方案** #### 1. **显式设置视图层级** - 使用 `bringSubviewToFront(_:)` 确保需要交互的按钮位于顶层: ```swift addSubview(bannerButton) addSubview(redBotButton) addSubview(testButton) // 强制将 bannerButton 提到顶层(测试用) bringSubviewToFront(bannerButton) ``` #### 2. **检查视图边界与交互区域** - 确保按钮的 `frame` 或 `bounds` 不被其他视图遮挡: ```swift // 调试:临时设置背景色以可视化视图边界 bannerButton.wantsLayer = true bannerButton.layer?.backgroundColor = NSColor.blue.withAlphaComponent(0.3).cgColor redBotButton.wantsLayer = true redBotButton.layer?.backgroundColor = NSColor.red.withAlphaComponent(0.3).cgColor ``` #### 3. **验证 `hitTest` 行为** - 重写父视图的 `hitTest` 方法,确认事件是否被错误拦截: ```swift override func hitTest(_ point: NSPoint) -> NSView? { let view = super.hitTest(point) print("Hit view: \(view?.description ?? "nil")") // 检查实际命中的视图 return view } ``` #### 4. **调整 `addSubview` 顺序** - 将需要优先交互的按钮最后添加(符合常规层级逻辑): ```swift addSubview(testButton) addSubview(redBotButton) // 最后添加的按钮在顶层 addSubview(bannerButton) // 如果 bannerButton 需要交互,应最后添加 ``` --- ### **根本原因推测** - 您的代码中可能存在以下情况之一: 1. **隐式视图重叠**:`bannerView` 或 `redBotView` 的图像范围超出了预期,遮挡了按钮。 2. **事件穿透**:父视图的某些属性(如 `isUserInteractionEnabled` 或 `acceptsTouchEvents`)未正确设置。 3. **SnapKit 约束计算误差**:约束生成的 `frame` 与预期不符,导致按钮实际可点击区域偏移。 --- ### **推荐修复代码** ```swift override func setupSubviews() { super.setupSubviews() // 1. 确保按钮类型支持交互 bannerButton.setButtonType(.pushOnPushOff) redBotButton.setButtonType(.pushOnPushOff) // 2. 添加子视图(将需要交互的按钮最后添加) addSubview(reminderTitleLabel) addSubview(remindWayLabel) addSubview(bannerView) addSubview(redBotView) addSubview(bannerLabel) addSubview(redBotLabel) addSubview(soundLabel) addSubview(soundSwitchButton) addSubview(seperatorView) addSubview(messageTypeTitleLabel) addSubview(eventMessageLabel) addSubview(eventMessageSwitchButton) addSubview(deviceMessageLabel) addSubview(deviceMessageSwitchButton) // 最后添加交互按钮(确保它们在顶层) addSubview(bannerButton) addSubview(redBotButton) // 3. 调试:可视化按钮区域 bannerButton.wantsLayer = true bannerButton.layer?.backgroundColor = NSColor.blue.withAlphaComponent(0.2).cgColor redBotButton.wantsLayer = true redBotButton.layer?.backgroundColor = NSColor.red.withAlphaComponent(0.2).cgColor } ``` --- ### **验证步骤** 1. **检查控制台日志**:通过 `hitTest` 调试确认实际点击的视图。 2. **可视化边界**:运行应用后观察按钮的背景色区域是否与预期一致。 3. **简化测试**:暂时移除其他视图,仅保留两个按钮,逐步排查干扰因素。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值