Search code examples
iosuiviewcontrollerswift4uibezierpathcabasicanimation

Gradually adding rectangle animation in iOS


I have a single view application in Xcode and doing the following in ViewController.swift. My objective is to have the screen filled up with a brown colored rectangle gradually over 5 seconds. Am I missing something or is the approach completely wrong?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let expandAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")
    expandAnimation.fromValue = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0))
    expandAnimation.toValue = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
    expandAnimation.duration = 5.0
    expandAnimation.fillMode = kCAFillModeForwards
    expandAnimation.isRemovedOnCompletion = false
    let rectLayer: CAShapeLayer = CAShapeLayer()
    rectLayer.fillColor = UIColor.brown.cgColor
    rectLayer.path = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0)).cgPath
    rectLayer.add(expandAnimation, forKey: nil)
    self.view.layer.addSublayer(rectLayer)
}

I don't want the color to gradually appear. I want a glass filling kind of effect. Imagine this

Water Filling Fancy

except for the fancy wavy effects.


Solution

  • After understanding your question better, you want to simulate the filing of a water glass (without the animation of the wave), you can achieve that through:

        let myLayer: CALayer = .init()
        myLayer.backgroundColor = UIColor.red.cgColor
        self.view.layer.addSublayer(myLayer)
    
        func animateFilling(to view:UIView)
        {
            var mFrame = CGRect(x: 0, y: view.frame.size.height, width: view.frame.size.width, height: 0)
            myLayer.frame = mFrame
            let fillingAnim = CABasicAnimation(keyPath: "bounds")
            fillingAnim.fillMode = kCAFillModeForwards
            fillingAnim.fromValue = mFrame
            fillingAnim.duration = 2
            fillingAnim.isRemovedOnCompletion = false
            mFrame.size.height = 1000
            fillingAnim.toValue = mFrame
            myLayer.add(fillingAnim, forKey: nil)
        }