Search code examples
swiftcore-animation

What's the difference between isRemovedOnCompletion and kCAFillModeForwards


I am confused about What's the difference between isRemovedOnCompletion and kCAFillModeForwards in Layer animation. I am reading a book about animation which suggesting using only kCAFillModeForwards to keep last frame presented.

But it didn't work with me so I did a search and I can see others suggesting combining kCAFillModeForwards and isRemovedOnCompletion to keep last frame presented. Last solution worked with me, but I am still confused, what's the difference between them?


Solution

  • You should not misuse isRemovedOnCompletion or kCAFillModeForwards for this purpose. I have seen this book and many examples use this "trick", but it is wrong. It is one of the worst misinformational memes ever to get promulgated around the Internet! It's just a crutch to make up for the fact that you have constructed the animation incorrectly.

    For example, consider this simple code:

    let opts : UIView.AnimationOptions = .autoreverse
    let xorig = self.v.center.x
    UIView.animate(withDuration:1, delay: 0, options: opts, animations: {
        self.v.center.x += 100
        }, completion: nil
    )
    

    The view animates 100 points to the right and then animates 100 points back to its original position — and then jumps 100 points back to the right. The reason is that the last actual value we assigned to the view's center x is 100 points to the right, so when the animation is over and the "animation movie" is whipped away, the view is revealed still sitting 100 points to the right.

    The solution is to move the view back to its original position, yourself! You can do that in the completion: function:

    let opts : UIView.AnimationOptions = .autoreverse
    let xorig = self.v.center.x
    UIView.animate(withDuration:1, delay: 0, options: opts, animations: {
        self.v.center.x += 100
        }, completion: { _ in
            self.v.center.x = xorig
    })
    

    All misuses of kCAFillModeForwards and isRemovedOnCompletion are based on a failure to do that sort of thing. Either in view animation or explicit layer animation, the programmer has neglected to give the animated property the value that it will have at the end of the animation. So what the confused programmer then does is cheat, sweeping the problem under rug. kCAFillModeForwards means "keep the animation at its endpoint when it ends". Setting isRemovedOnCompletion to false means that the animation never ends! That is a terrible idea; it puts an unnecessary strain on the rendering engine, and it is completely misguided and unnecessary. Basically you are covering the real position of the view/layer with the animation position. That is wrong. Never follow those examples. Learn how to write an animation correctly and do so.