skip to Main Content

I have a custom UIPresentationController in which I overrode the presentedView as follows:

override var presentedView: UIView? {
        guard let view = super.presentedView else { return nil }
        
        let shadowLayer = CALayer()
        shadowLayer.shadowPath = .init(rect: view.bounds, transform: .none)
        shadowLayer.shadowRadius = 6
        shadowLayer.shadowColor = .init(gray: 0, alpha: 0.15)
        shadowLayer.backgroundColor = view.layer.backgroundColor
        shadowLayer.shadowOpacity = 1
        shadowLayer.shadowOffset = .init(width: 0, height: -10)
        shadowLayer.shouldRasterize = true
        shadowLayer.rasterizationScale = UIApplication.screen?.scale ?? 1.0
        
        view.layer.insertSublayer(shadowLayer, at: 0)
        shadowLayer.position = view.layer.position
        shadowLayer.bounds = view.bounds
        view.layer.masksToBounds = false
        
        return view
    }

Then for efficiency I thought why creating a new CALayer every time presetedView is calculated and decided to hold the the layer as a property of the class and only update the shadowPath. After that the layer is no longer visible and not in the view hierarchy anymore. I also tried to insert sublayer only once by checking if layer is present in the sublayers but it didn’t help

Does anyone know what am I missing?

UPDATE:
Declared a property

private let shadowLayer = {
        let shadowLayer = CALayer()
        shadowLayer.shadowRadius = 6
        shadowLayer.shadowOpacity = 1
        shadowLayer.shadowOffset = .init(width: 0, height: -10)
        shadowLayer.shouldRasterize = true
        shadowLayer.rasterizationScale = UIApplication.screen?.scale ?? 1.0
        shadowLayer.masksToBounds = false
        return shadowLayer
    }()

And deleted initialization code from here. After that the layer dissappears

    override var presentedView: UIView? {
        guard let view = super.presentedView else { return nil }
        

        shadowLayer.shadowPath = .init(rect: view.bounds, transform: .none)

        shadowLayer.shadowColor = .init(gray: 0, alpha: 0.15)
        shadowLayer.backgroundColor = view.layer.backgroundColor

        
        view.layer.insertSublayer(shadowLayer, at: 0)
        shadowLayer.position = view.layer.position
        shadowLayer.bounds = view.bounds
        view.layer.masksToBounds = false
        
        return view
    }

2

Answers


  1. Chosen as BEST ANSWER

    Turns out I was calculating layers position & shadowPath wrong! Because sublayers coordinating system is relative to superlayers system we should draw path inside views bounds not frame and calculate center point of the frame manually

        override var presentedView: UIView? {
            guard let view = super.presentedView else { return nil }
            
            
            shadowLayer.shadowPath = .init(rect: view.bounds, transform: .none)
            shadowLayer.position = .init(x: view.bounds.midX, y: view.bounds.midY)
            shadowLayer.bounds = view.bounds
            shadowLayer.backgroundColor = view.layer.backgroundColor
    
            
            if shadowLayer.superlayer == nil {
                view.layer.insertSublayer(shadowLayer, below: nil)
            }
            
            view.layer.masksToBounds = false
            
            return view
        }
    

  2. You could simply add code to define your shadowLayer as an instance variable and initialize it at the same time:

    var shadowLayer = CALayer()
    

    (You could also make it a lazy property.)

    Make that change to your code above, and then just reference the existingshadowLayer in your code rather than defining it (and initializing it) in your function.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search