Introduction into SwiftUI animations
iOS SwiftUI animation GeometryEffect Estimated reading time: 10 minutesiOS provides for us a lot (really, a lot) different variants of animation mechanisms. CoreAnimation
, UIKit
animations, SpriteKit
, SceneKit
, OpenGL ES
etc. When Apple introduces for us SwiftUI
, animation can’t be just skipped. Instead, the new mechanism for animation was introduced for us.
Animation brings life and a better experience (UX
) into your application. It can be small, it can be short, even hardly noticeable, but it always improves UX
. Even if most users didn’t see it in most cases, u can notice that when u remove animation - everyone feels that something is wrong, something is missing.
Animations
Some aspects of our apps can be animated implicitly, other explicitly.
I always prefer the second approach - in this way u always sure, that result will be the same, the one that u expect to have.
Different versions of iOS can behave in a different way (especially with
SwiftUI
on iOS 13 and iOS 14). This may bring inconsistency to our app. This is one more reason, why u always should control your animations.
As I mention, animations can be divided into 2 groups - explicit and implicit.
If we switch back to UIKit
, we remember the same behavior - some properties can be animated automatically for us:
To animation this property from CALayer
, for example, the system requires no code from us - every time we change it, the system will animate this change for us implicitly.
Same true and for SwiftUI
.
From the very first minute of testing it, u can notice, that some transformations and changes can be animated for u automatically. This is a great approach that sometimes simplifies things for us.
As u can remember from UIKit
, UIView
has a lot of properties that can be animated for u. animatable
- such comment can be found in a header file for some of the props in UIView
. Same true and for various layers:
Such comments open for us different possibilities of animations. We know what we can animate and what, well, we can with additional effort.
check about
UIVew
animation here
Animatable
SwiftUI
introduces for us even more possibilities - we can use the Animatable
protocol.
Requirements are pretty simple - provide the value that u would like to animate via special variable animatableData
that should adopt VectorArithmetic
. In other words - something that can be changed depending on animation progress.
To make thing even more comfortable for usage Apple added an extension for this protocol:
U may wonder, how to animate few properties of one type in the same moments? The answer is - use AnimatablePair
or a combination of it:
AnimatablePairs
can contain nestedAnimatablePairs
- so the number of elements that can be animated are limited only to your imagination
For now, half of the process should be clear - the selection of WHAT to animate. Another half of the question - HOW to determine the progress of animation and HOW it can be calculated.
For this purpose, SwiftUI
uses the same idea as was used in UIKit
- duration of animation and animation curve in a combination of initialValue with a target value.
Let’s review each component of this.
The very first one is duration. It’s pretty simple - we just specify how long animation should be:
As u can see, here we use .easeOut
- one of the predefined animation curves. The other few predefined are - linear
, easeIn
, easeOut
, easeInOut
.
The animation curve describes the relative frame rate for the animation; predefined curves are linear, ease in (slow down near end), ease out (slowly speed up at the start), and ease in-ease out (S-curve). from Apple doc
U can play a bit with animation curves and check how they work using a great source for this available here
To summarize, duration and curve are used to determine how to change progress over time. These values as a result return for us progress
.
InitialValue with target value is used to determine how to get value
that used to build and show the object in a concrete moment during the animation. Imagine for example Rect that changes size - from 2x2 to 5x5 over 3 sec with a linear curve. This means that every second the size will be changed by 1. so in a second after animation started the size will be (2+1)x(2+1) where 1 calculated as (5-2) / 3 * 1 and 5 - is targetValue, 2- initial value, 3 duration and 1 is current progress. So the fraction of change can be calculated as follows:
And the whole value should also include initialValue intho this approach:
Now, it’s more visible, why the animatableData
property from the Animatable
protocol required to adopt VectorArithmetic
.
I should also mention that explicit animation in SwiftUI
can be created using withAnimation
function.
Normally, in this function, we perform some change(s), and everything that depends on value(s) change will be animated. If we go a bit in detail, SwiftUI
checks all available animatableData
and animate it using the described above approach.
Adepts of Animatable
Few types used in SwiftUI
already adopt Animatable
. That’s how we can use animate
viewModifier without even writing a line of code.
Available ready to use options are:
AnimatableModifier
EdgeInsets
GeometryEffect
Shape
StrokeStyle
UnitPoint
Angle
CGSize
,CGPoint
- other
All these types already conform to Animatable
and ready to use and to make alive u’r animations.
That’s how when u animate change of available Shapes
or Edges
of Rect
we got animation.
I wrote small sample about
GeometryEffect
here
Example
Let’s now taste the code.
I won’t create something complex and difficult here. Instead, I will try to provide very simple examples of usage of every mechanism that was described above.
You can refer to SwiftUI-lab samples, ObjC.io samples or Hacking with Swift. These resources are great. Some samples idea I grab from these articles, but I tried to make them even more simple. I also cover here my own experience within animations in
SwiftUI
with the hope, that someone can found it useful in some way.
To experiment with animations we will use a very simple view with some buttons and objects that can be animated.
The most simple sample - is to create our own AnimatableModifier
. We may create it using the already created for us by Apple modifier. This will allow us to focus on the process itself instead of some logic required for modification. To do so, we will use scaleEffect
:
We adopt AnimatableModifier
protocol and provide animatableData
. In the body, we provide logic - what we do within content
to achieve the required effect (as I mention above, for simplicity we just use the existing modifier). All other things SwiftUI
will handle for us.
Result:
To change a few properties we should use AnimatablePair
. To demonstrate this, let’s create a modified version of the same effect.
We used GeometryEffect
as a modifier in which AnimatablePair
of X
and Y
values are used to describe animatable change of X
and Y
scale.
Result:
To modify How animation is executed we may use an animation curve. To create a custom one we should describe a duration curve.
For example, if u want to make something like “jump” animation (when progress will return a bit after processing, something similar to spring) we may create next:
Result:
Now we can switch to transition. The most simple one we create again by using an existing modifier, just to get the idea of how it works. Let’s use opacity
this time.
Remember, to make the transition work, a view should be added/removed from hierarchy, in other cases, u can’t see any transitions
The test UI will display the Button
and Circle
shape.
Result:
We can use various techniques to create the transition we want.
With a shape fill effect:
Result:
Or using GeometryEffects
:
Result:
Or even combining any of transitions:
Conclusion
SwiftUI
is not an exception element in regards to animation from Apple toolset. Instead, it brings us even more possibilities to create from simple to insane animations and to enhance app UX.
In this article, I tried to cover the basic techniques required for work with animations in SwiftUI
.
I strongly recommend everyone who interested in animation to try all techniques by own and taste how it works.
Reading list:
Share on: