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

自定义UIPresentationController中CALayer存为属性后消失问题

问题分析与解决方案

你的问题核心在于**CALayer不能同时隶属于多个父图层**,且重复执行insertSublayer会导致图层被频繁转移,最终脱离视图层级。以下是具体解决思路和代码修改:

问题根源

每次调用presentedView时直接执行view.layer.insertSublayer(shadowLayer, at: 0),会触发以下问题:

  1. 同一个shadowLayer被重复插入时,会先从原父图层移除,再添加到新图层,这个过程可能因视图生命周期时机问题导致图层丢失;
  2. 没有判断图层是否已属于当前视图的层级,重复操作破坏了图层的附着关系。

修复代码

第一步:优化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:47:22