iosswiftcatransition

CATransition type fade seems broken


When working on this question, I notice that maybe fade of CATransitionType in CATransition is not working or broken. The rest of CATransitionType: moveIn, push, reveal works correctly.

I'm working on iPhone 13, iOS 16.0.

Code of the transition:

extension CALayer {
    func makeFadeTransition() {
        let transition = CATransition()
        transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        transition.duration = 0.5
        transition.type = .fade
        self.add(transition, forKey: nil)
    }
}

Usage:

self.customView.layer.makeFadeTransition()

I know that we can switch to using UIView.animate combined with alpha to change opacity instead.

UIView.animate(withDuration: 0.15, animations: {
    self.customView.alpha = 0.0
})

or using CABasicAnimation:

extension CALayer {
    func makeFadeTransition() {
        let transition = CABasicAnimation(keyPath: "opacity")
        transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        transition.duration = 0.5
        transition.fromValue = 1.0
        transition.toValue = 0.0
        self.add(transition, forKey: nil)
    }
}

But again, is CATransitionType type fade broken, or am I wrong at something?


Solution

  • You have to do something to change the layer...

    For example, to fade-out / fade-in, we could do this:

    extension CALayer {
        func makeFadeTransition() {
    
            let transition = CATransition()
            transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            // let's use duration of 2.5 to make it more obvious
            transition.duration = 2.5
            transition.type = .fade
            
            // change the layer... opacity, backgroundColor, frame, etc
            
            // fade transition doesn't like opacity of 0.0, so we'll use 0.01
            self.opacity = self.opacity == 1.0 ? 0.01 : 1.0
            
            // or, for example,
            // "shrink" the layer by 20-points
            //self.frame = self.frame.insetBy(dx: 20.0, dy: 20.0)
        
            self.add(transition, forKey: nil)
            
        }
    }