如何绑定两个视图的z轴关系使二者z-index始终相邻?
视图层级相邻绑定解决方案
以下方案适用于iOS UIKit、macOS AppKit场景,可实现两个固定视图始终保持相邻层级的需求:
最优低成本实现
如果没有强制要求两个绑定视图必须作为父视图的直接一级子视图,优先选择容器嵌套方案:
- 新增空白的容器视图
ContainerView,将需要绑定的ViewA1和ViewA2添加到ContainerView中,调整好两者的相邻层级 - 再将
ContainerView添加到原父视图ViewA的对应层级位置 - 此时所有外部新增的视图只会插入到
ContainerView的上方或下方,不会进入容器内部,天然保证ViewA1和ViewA2永远相邻,无需额外开发逻辑。
自定义父视图实现方案
如果必须保留两个视图作为父视图的直接子视图,可通过重写父视图的子视图插入方法实现:
- 自定义
ViewA的子类,新增两个属性持有需要绑定的ViewA1和ViewA2,可新增开关属性控制绑定功能是否生效 - 重写父视图所有子视图操作相关方法:
addSubview:、insertSubview:atIndex:、insertSubview:belowSubview:、insertSubview:aboveSubview:、exchangeSubviewAtIndex:withSubviewAtIndex: - 所有方法执行原有逻辑后,调用统一的层级修正方法,强制将两个绑定视图调整为相邻状态
示例代码(Swift版本):
class CustomParentView: UIView { var boundUpperView: UIView? var boundLowerView: UIView? var isHierarchyBindingEnabled = true override func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView) { // 若要插入到上层绑定视图下方,改为插入到下层绑定视图下方 if siblingSubview == boundUpperView, isHierarchyBindingEnabled { super.insertSubview(view, belowSubview: boundLowerView!) fixBoundHierarchy() return } super.insertSubview(view, belowSubview: siblingSubview) fixBoundHierarchy() } private func fixBoundHierarchy() { guard let upper = boundUpperView, let lower = boundLowerView, isHierarchyBindingEnabled else { return } // 强制保持下层绑定视图永远在上层绑定视图的正下方 insertSubview(lower, belowSubview: upper) } }
其余子视图操作方法按相同逻辑修改即可。
全局监听实现方案
如果无法修改父视图的类,可通过Runtime方法交换实现全局监听:
- 用Runtime交换UIView的
didAddSubview:、willRemoveSubview:方法 - 每次子视图发生变化时,调用上述层级修正方法,强制调整两个绑定视图的相对位置
注意事项
- 如果使用
layer.zPosition控制层级,需要固定两个绑定视图的zPosition差值,且差值要大于普通视图的zPosition最大调整范围,避免第三方视图插入到两者中间 - 不要尝试直接监听
subviews数组属性,该属性默认不会触发KVO通知,实现成本远高于上述两种方案
内容的提问来源于stack exchange,提问作者jalxp
相关产品推荐
相关产品推荐

