1

I am trying to create an app home screen animation from splash, like after launch screen completed (full)screen color transforms into an app logo background color. Currently below code kind of archive what I expected. But, that transformation CAShapeLayer doesn't do with corner radius. Without corner radius it works as normal, when I try to use circle/oval/corner radius animation seems like below gif.

Tried few other StackOverflow answers which create circle animation those are not working. Here one of those.

    weak var viewTransitionContext: UIViewControllerContextTransitioning!

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        viewTransitionContext = transitionContext

        guard let fromVC = viewTransitionContext.viewController(forKey: .from) else { return }
        guard let toVC = viewTransitionContext.viewController(forKey: .to) else { return }

        if fromVC.isKind(of: SOGSplashViewController.self) && toVC.isKind(of: SOGHomeViewController.self) {
            guard let toVCView = transitionContext.view(forKey: .to) else { return }
            guard let fromVCView = transitionContext.view(forKey: .from) else { return }

            let containerView = transitionContext.containerView
            let labelWidth = UIDevice.width() * 0.75
            let labelHeight = labelWidth * 0.7
            let xAxis = (UIDevice.width() - labelWidth)/2.0
            let yAxis = ((UIDevice.height()/2.0) - labelHeight)/2.0
            let labelRect = CGRect(x: xAxis, y: yAxis, width: labelWidth, height: labelHeight)
            let radius = (UIDevice.height()/2.0)*0.1
            let fromFrame = fromVCView.bounds
            let animationTime = transitionDuration(using: transitionContext)

            let maskLayer = CAShapeLayer()
            maskLayer.isOpaque = false
            maskLayer.fillColor = fromVCView.backgroundColor?.cgColor
            maskLayer.backgroundColor = UIColor.clear.cgColor
            maskLayer.path = toPathValue.cgPath

            let maskAnimationLayer = CABasicAnimation(keyPath: "path")
            maskAnimationLayer.fromValue = (UIBezierPath(rect: fromFrame)).cgPath
            maskAnimationLayer.toValue = toPathValue.cgPath
            maskAnimationLayer.duration = animationTime
            maskAnimationLayer.delegate = self as? CAAnimationDelegate

            containerView.addSubview(fromVCView)
            containerView.addSubview(toVCView)
            fromVCView.layer.add(maskAnimationLayer, forKey: nil)
            maskLayer.add(maskAnimationLayer, forKey: "path")
            containerView.layer.addSublayer(maskLayer)

            let deadLineTime = DispatchTime.now() + .seconds(1)
            DispatchQueue.main.asyncAfter(deadline: deadLineTime) {
                UIView.animate(withDuration: 0.2, animations: {
                    maskLayer.opacity = 0
                }, completion: { (isSuccess) in
                    self.viewTransitionContext.completeTransition(true)
                })
            }
        }
    }

enter image description here

Mathi Arasan
  • 869
  • 2
  • 10
  • 32

1 Answers1

1

Transforming a rectangular path to a rounded rectangular path is a very complex operation if you do it through a generic way like Core Animation.. You should better use the cornerRadius property of CALayer which is animatable.

Here is a working example with a constraint based animation:

class ViewController: UIViewController {
    @IBOutlet var constraints: [NSLayoutConstraint]!
    @IBOutlet var contentView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        self.contentView.layer.cornerRadius = 10.0
        self.animate(nil)
    }

    @IBAction func animate(_ sender: Any?) {
        for c in constraints {
            c.constant = 40.0
        }
        UIView.animate(withDuration: 4.0) {
            self.view.layoutIfNeeded()
            self.contentView.layer.cornerRadius = 40.0
        }
    }
}

contentView points to the inner view which should be animated, and constraints refer to the four layout constraints defining the distances from the view controller's view to the content view.

example

This is just a simple, rough example, which can certainly be improved.

clemens
  • 16,716
  • 11
  • 50
  • 65
  • Thanks for the option. Initial I tried with constraint based animation only. One more screen also having like this animation (App store today's home), swipe back or tap on back button animation will be easier if do it on `UIViewControllerContextTransitioning` – Mathi Arasan Mar 04 '20 at 16:00