自定义UIPresentationController中CALayer存为属性后消失问题
问题分析与解决方案
你的问题核心在于**CALayer不能同时隶属于多个父图层**,且重复执行insertSublayer会导致图层被频繁转移,最终脱离视图层级。以下是具体解决思路和代码修改:
问题根源
每次调用presentedView时直接执行view.layer.insertSublayer(shadowLayer, at: 0),会触发以下问题:
- 同一个
shadowLayer被重复插入时,会先从原父图层移除,再添加到新图层,这个过程可能因视图生命周期时机问题导致图层丢失; - 没有判断图层是否已属于当前视图的层级,重复操作破坏了图层的附着关系。
修复代码
第一步:优化shadowLayer初始化(固定属性提前设置)
private let shadowLayer = { let shadowLayer = CALayer() shadowLayer.shadowRadius = 6 shadowLayer.shadowOpacity = 1 shadowLayer.shadowOffset = CGSize(width: 0, height: -10) shadowLayer.shouldRasterize = true shadowLayer.rasterizationScale = UIScreen.main.scale // 替换为系统标准写法,避免自定义属性风险 shadowLayer.masksToBounds = false shadowLayer.shadowColor = UIColor(gray: 0, alpha: 0.15).cgColor // 固定属性移到初始化,避免重复设置 return shadowLayer }()
第二步:修改presentedView重写逻辑
override var presentedView: UIView? { guard let view = super.presentedView else { return nil } // 仅当图层未附着在当前视图时,才执行添加操作 if shadowLayer.superlayer !== view.layer { shadowLayer.removeFromSuperlayer() // 先从旧父图层移除(如果存在) view.layer.insertSublayer(shadowLayer, at: 0) } // 动态更新随视图变化的属性 shadowLayer.shadowPath = UIBezierPath(rect: view.bounds).cgPath shadowLayer.backgroundColor = view.layer.backgroundColor shadowLayer.position = view.layer.position shadowLayer.bounds = view.bounds view.layer.masksToBounds = false return view }
关键优化点说明
- 判断superlayer归属:确保图层只被添加到当前视图的层级,避免重复插入导致的图层转移丢失;
- 提前移除旧附着:当presentedView更换时(比如重新present新视图),确保图层能正确切换到新的父图层;
- 分离固定与动态属性:将shadowColor这类不会变化的属性移到初始化闭包,减少重复设置的性能开销。
内容的提问来源于stack exchange,提问作者PigeonPO
相关产品推荐
相关产品推荐

