Creating Animations with UIKit and Core Animation

栏目: IT技术 · 发布时间: 4年前

内容简介:We, developers, have a lot of options when it comes to animations nowadays. There is plenty of libraries that can be used to easily integrate an animation prepared by a designer into our applications. The most popular (probably) is a Lottie which is availa

Creating animations with UIKit and Core Animation

We, developers, have a lot of options when it comes to animations nowadays. There is plenty of libraries that can be used to easily integrate an animation prepared by a designer into our applications. The most popular (probably) is a Lottie which is available for both iOS and Android. It's also possible to use Lottie for many multi-platform solutions like Flutter or React Native which makes it super convenient. There is also Rive, a great web-based tool for animations that has a plugin for Flutter as well as an iOS framework (it hasn't been updated for a while but should still work as far as I know). Those tools are great but most developers are not designers and do not know or do not want to play with graphics outside the code.

We have also libraries like Hero or Spring that can help you make simple transitions and animations without using any external tools for designers. However, it is pretty often that we have to implement something completely custom and can't use any already created framework. Or maybe you are like me and do not like to add too many dependencies to your projects and rather want to implement such things yourself. Either the reason is, as I said in my previous article about iOS Interview Questions, no matter what it is good to know such things as you might ie. be asked about this during the interview.

There are a few methods that we can use while working with animations. Let's take a closer look at 3 of then: Core Animation , widely known UIView.animate and UIView 's keyframes.

Core Animation

Core Animation is a framework designed by Apple and is available on all the platforms supported by the company. That means you can only learn it once and take advantage of it on either iOS, macOS, tvOS and watchOS. You might not be aware of it but even if you have never heard about this framework before, you are still using CoreAnimation for all your applications you create.

Core Animation framework is quite powerful, sadly it's not that convenient to use. It's not that hard either though, all you have to do is to configure a few animation parameters and attach it to the view's layer.

Here is an example of an animating view's cornerRadius that auto reserves and repeats infinitely. Those two parameters are optional and if not set, the animation will just play once.

let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.cornerRadius))
animation.fromValue = 0
animation.toValue = 16
animation.duration = 1
animation.autoreverses = true
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)

squareView.layer.add(animation, forKey: "squareView.cornerRadius")

There is a small trick when playing animation only once though. The layer will reset to its initial value which might be confusing. When googling for an answer you might find a solution that suggests using those 2 properties to make it not reset it's value to the initial one.

animation.fillMode = CAMediaTimingFillMode.forwards
animation.isRemovedOnCompletion = false

There is another trick with this solution though. The animation is never removed, as well as the actual value of cornerRadius is never set to the expected one. So we can either set the cornerRadius to the desired value right before playing the animation and thanks to the animation.fromValue = 0 it will animate just fine. Or, we can use a delegate animation.delegate = self and implement func animationDidStart(_ anim: CAAnimation) method where we will set it to correct value, like this:

extension MyViewController: CAAnimationDelegate {
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        print("\(squareView.layer.cornerRadius)")
    }
}

It is also fairly easy to set multiple values and animate between them.

let animation = CAKeyframeAnimation(keyPath: #keyPath(CAShapeLayer.cornerRadius)
animation.values = [0, 50, 16, 50, 0]
animation.keyTimes = [0, 0.25, 0.5, 0.75, 1]
animation.duration = 3
animation.isAdditive = true

squareView.layer.add(animation, forKey: "squareView.cornerRadius")

The values and keyTimes elements count must match each other and the keyTimes contains a value between 0 and 1, where 0 is the beginning of the animation and 1 is its end.

There is also one cool class that might be handy - CASpringAnimation - it inherits from the CABasicAnimation and makes the spring animations way easier to achieve. Give it a try! You can achieve a lot of great effects using it together with UIViews or Core Graphics framework.

UIView.animate

You might never have a chance to use Core Animation directly but I am pretty sure - if you are not a complete beginner as iOS developer - you have heard of this animation method.

The Core Animation method I described above has one big disadvantage though... you can only animate a single property with it. You can animate multiple by creating a group...

let group = CAAnimationGroup()
group.animations = [...]

... but it's still a lot of code to write for such a simple thing. That's why we have a more convenient method which everyone is familiar with.

animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)

as well as a few more animate methods on UIView class that have some more arguments and are more configurable. With those methods, we can easily animate any animatable property from within the same animation block (closure). Also, we do not have to worry about layer/view resetting to its initial value as we directly change the actual value.

To achieve the first example all we need to do is call one simple method:

UIView.animate(withDuration: 1) {
    self.squareView.layer.cornerRadius = 16
}

It gets "funnier" when we want to make several steps in our animation since it can quickly become a messy and unreadable, just take a look:

UIView.animate(withDuration: 0.5, animations: {
    self.squareView.layer.cornerRadius = 16
}) { _ in
    UIView.animate(withDuration: 0.5, animations: {
        self.squareView.layer.cornerRadius = 50
    }) { _ in
        UIView.animate(withDuration: 0.5, animations: {
            self.squareView.layer.cornerRadius = 16
        }) { _ in
            UIView.animate(withDuration: 0.5, animations: {
                self.squareView.layer.cornerRadius = 50
            }) { _ in
                UIView.animate(withDuration: 0.5, animations: {
                    self.squareView.layer.cornerRadius = 0
                })
            }
        }
    }
}

Also, it's way harder to manage the duration of the whole animation as we could have to calculate ourselves the fraction of duration for each step.

UIView Keyframes

And finally, the latest and least known addition to the UIKit framework - keyframes. It's been added a really long time ago (iOS 7) but still, I rarely see this in any project I have been involved in.

So let's take a look at a similar example:

UIView.animateKeyframes(withDuration: 3, delay: 0, options: [], animations: {
    UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25) {
        self.squareView.layer.cornerRadius = 50
    }

    UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25) {
        self.squareView.layer.cornerRadius = 16
    }    

    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) {
        self.squareView.layer.cornerRadius = 50
    }

    UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
        self.squareView.layer.cornerRadius = 0
    }
})

It's way cleaner and readable than the previous solution although it has its disadvantages. Not everyone likes to work with relative duration and there is no easy way to create Spring Animation using this method.

Conclusion

When it comes to animations, we have quite a lot of ways to integrate them into our applications. Which one to choose you might ask? It all depends on your experience and the requirements since not all methods are good for some outcomes. Also, each solution has its own advantages and disadvantages.

Going with a 3rd party framework might be the easiest to implement but ie. Lottie or Rive might require some design skills or a designer friend that has experience with animations and can help us out. Thankfully there is a lot of free Lottie and Rive animations that we could use. Those libraries might be good for really complex animations but if we need something simpler or we simply do not want to add an additional framework to our project, we might want to go with the native method.

When to choose Core Animation and when the well known UIView.animate ? Let's be honest, most of the time you will want to implement your animation with the 2nd option or use UIView Keyframes for something a little bit more complex (although not too complex :see_no_evil:) since it's really convenient to use and it's just not worth over complicating it with Core Animation . CA might be still useful though if we run into troubles with UIKit method and if something seems impossible with UIView.animate it might be actually possible with Core Animation .

Thank you for reading! Got any questions? Feel free to poke me on Twitter .


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创新者

创新者

[美] 沃尔特 · 艾萨克森 / 关嘉伟、牛小婧 / 中信出版社 / 2016-6 / 88.00

讲述了计算机和互联网从无到有的发展历程,并为我们生动地刻画出数字时代的创新者群像。 在近200年的数字化进程中群星闪耀,艾萨克森从一个计算机程序的创造者、诗人拜伦之女埃达说起,细数了这一群站在科学与人文交叉路口的创新者,他们包括通用型电子计算机的创造者奠奇利、科学家冯·诺依曼、仙童半导体公司的“八叛逆”、天才图灵、英特尔的格鲁夫、微软的比尔·盖茨、苹果公司的乔布斯、谷歌的拉里·佩奇等。《创新......一起来看看 《创新者》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具