Search code examples
swiftuiviewcgaffinetransform

Chaining UIView animation with CGAffineTransform scale & translate


I am trying to animate a UIView in a Playground using animate(withDuration:animations:). The goal is to move a view down, then move it right while also scale it up.

So I am doing it in 2 steps, calling a second animation after the first one is completed.

Here are 3 transformations I am going to apply to my view

let scaleUp = CGAffineTransform(scaleX: 2, y: 2)
let moveDown = CGAffineTransform(translationX: 0, y: 100)
let moveRight = CGAffineTransform(translationX: 100, y: 0)

To do moveDown followed by moveRight I concatenate the second one to the first one.

UIView.animate(withDuration: 2, animations: {
            circleView.transform = moveDown
        }) { _ in
            //First animation completed
            UIView.animate(withDuration: 4, animations: {
                circleView.transform = moveDown.concatenating(moveRight)
            })
        }

transition 1 `


Now, when I am trying to scale the view up while moving to the right, it seems like it is applying scale to already transformed view, which results in shifting everything down (2 times) before the second animation starts.

UIView.animate(withDuration: 2, animations: {
            circleView.transform = moveDown
        }) { _ in
            //First animation completed
            UIView.animate(withDuration: 2, animations: {
                circleView.transform = moveDown.concatenating(scaleUp.concatenating(moveRight))
            })
        }

enter image description here

How can I achieve move right + scale up without reseting my initial transformation?


Solution

  • My solution is more like a hot fix but it's what you want:

    1 perform animation of move down transformation

    2 revert above transformation (without animation)

    3 set circleView to position like after move down transformation (without animation)

    4 perform animation of move right and scale up

    UIView.animate(withDuration: 2, animations: {
            circleView.transform = moveDown //1
        }) { _ in
            //First animation completed
            circleView.transform = .identity //2
            circleView.frame.origin.y += 100 //3
            UIView.animate(withDuration: 2, animations: {
                circleView.transform = moveRight.concatenating(scaleUp) //4
            })
        }