UIKit Animation (Part 1)
Prerequisite → Strong understanding of Auto layout
Animation:
A change in value or state over time.
Animate Constraint Constant
As shown in Figure 1, we created a view with an initial height of 0 when the user tap on the toggle button, we will change its height at run time and with animation
When the user tap on the toggle height button, we change the height constraint constant using the reference constraint outlet. If the constraint has changed your layout will automatically be marked as needing an update. This means that UIKit knows it has to update the layout for you and that’s why we saw the view height updated. We can also force auto layout updates to happen on demand you can ask for view to be laid out immediately by calling layoutIfNeeded
method. Currently if you tap on button it will update it’s height but not in a animated way. Now let’s add animation effect (smooth height change).
So in short if you change constraint it will update your view on next render pass and if you call layoutIfNeeded
it will do in same render cycle
As shown in Gif 1 after put force layout update on animation block using UIView.animate
, you can feel the animation effect. It will change the height of View with the animation duration 0.5, and start immediately since we added delay with 0 value
duration →
The total duration of the animations, measured in seconds. If you specify a negative value or 0
, the changes are made without animating them.
delay →
The amount of time (measured in seconds) to wait before beginning the animations. Specify a value of 0
to begin the animations immediately.
options →
A mask of options indicating how you want to perform the animations. For a list of valid constants, see UIView.AnimationOptions.
animations →
A block object containing the changes to commit to the views. This is where you programmatically change any animatable properties of the views (like height, position) in your view hierarchy. This block takes no parameters and has no return value. This parameter must not be NULL
.
completion →
A block object to be executed when the animation sequence ends. This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle. This parameter may be NULL
.
Actually calling layoutIfNeeded
will update the center in bounds for every view in the layout Any change that can be animated will be animated
As shown in Gif 2 when the toggle value is On we change the toggle button top constraint and view height and we only call layoutIfNeeded
one time only it will update all the pending constraint in the same render cycle
UIView Animation Options
To understand animation, options we will create a textfield and when user tap on toggle button , textfield will appear on the screen from left to right in an animated way . As shown in Figure 4 we created texfield and added view constraint , width ≥ 200 , center X,
As shown in Figure 5.1 and 5.2 ,initially we make thhe view to be outof screen by manipulating it’s centerX constrint outlet reference
.curveEaseIn
This one is moving slowly at first and then speeds up towards the end of the animation as shown in gif 3
.autoreverse → Combined with .repeat this will loop the animation indefinitely. Just using autoreverse will do the initial animation but in reverse, and then snap back to the end position of the initial animation
.curveEaseOut → Much easier to see than .curveEaseOut this option begins with the animation moving quickly and then slows down at the end.
.curveEaseInOut → Moves slowly at first, speeds up over middle portion, then slows down at the end of the animation.
.curveLinear → Animation occurs evenly across the whole duration.
.repeat → Simply repeats the animation, which means it is sent back to the starting position of the animation.
.autoreverse with .repeat → Autoreverse sends the animation back to its original position, .repeat then repeats that process so it looks like the image is moving in an infinite loop as shown in gif4
You can all gif compelet visual exapaation on this blog written by Alex Mason. There are other animation options which are relevant to transition will talk later in this blog
Dynamic View Animation
As shown in Figure 6, when we tap on the button, it will do a few things
- Created a view and added constraints to met the linear equation constraint formula
- Created an
aspect ratio 1:1
(by adding the relationship between width and height constraints)
As shown in Gif 5, the animation is starting from the upper left corner, it should start from the one we showed in Figure 3 it seems the layout engine is ignoring out starting constraints. It because we never called layoutIfNeeded
to settle the starting point and when we force layout it don’t have starting point so it starts from upper left corner
As shown in Figure 7, we settled the starting point by calling self.view.layoutIfNeeded()
and then do the animation, Now run the with this code you can see animation will start with this starting point
Now let’s add hide animation as well after 2 seconds
delay it will reset the values as well to show the hiding effect
Animate Constraint Multiplier
As shown in Figure 9, we have view that have height = 0.25 * superview
using multiplier, which is main rootView
, Now when user tap on toggle button we will animate multiplier to 0.5
Constraints are held by the closest view that contains both items in the constraint. Constraints that are held by a view don’t constitute an exhaustive list of constraints that affect a view. Every Constraint that affects a view is listed in the size inspector. Constraints that view holds are listed on the left in the document outline. A Constraint between its subview and superview is held by superview. A constraint between two subviews is held by the superview of both
As shown in Figure 10, it prints empty constraint since subView view don’t hold any constrints, as we discussed above Constraints are held that holds constraints that affects a view
Changing the multiplier
is not straight forward as compare to changing constraint constant
since multiplier
is read only , you need to create new constraint with new multiplier
and replace with older one
First step is add identifier
As shown in Figure 13 , we did few things
- Get constraint that held subview height constraint and delete constrint by using
isActive
= false . If we deactivate the constraint like this and don’t hold the reference to it , it will be deleted from memory the next time the layout is updated - Then we inject new constraint and activated it
- Force layout update using smooth animation technique
You can do other techniques as well , create two height constraint outlet, initially unchecked install button of the one and only change isActive
property
Spring Animation
So far we animated constraint properties to get from value A to value B, when you introduce springs, the value will still begin and end where you specify but over the duration of the animation , the value might overshoot value B and oscillate back and forth before finally stop there.
usingSpringWithDamping → The damping ratio for the spring animation as it approaches its quiescent state. To smoothly decelerate the animation without oscillation, use a value of 1
. Employ a damping ratio closer to zero to increase oscillation. higher values make the bouncing finish faster and less oscillation as shown in gif 6. 0.2
makes more bouncing and high osccillation as compare to 0.8
initialSpringVelocity → Inital momentum, Intially punch as shown in gif 7, high value give high initial punch as compare to low value
if you specfiy options with spring animations, it do a custom options to match the spring as well
We will use this Gif 3 code , and implement using spring animation
View Transitions
UIKit has a separate animation API to create predefined view transitions, which are quick , animated way to show and hide views or add and remove views from view heiarchy. So we will use this built in animation only when adding, removing, hiding or showing view respective property
As shown in Gif 9 , we used transition animation to show view using trigger isHidden
It’s the more straightforward one.View transitions are predefined, which means they’re somewhat limited, but very powerful and simple to implement. To implement the transition, you have to do one simple thing: pair a transition trigger with a predefined transition.
There are three triggers that should cause a view to transition: Use any of them inside the animation closure on a subview of the specified container view to start the transition animationisHidden →
this one triggers a view’s isHidden
property and causes it to disappear from view
.addSubview() →
this method adds a subview to a view’s view hierarchy.
removeFromSuperview() →
this does the opposite and removes a view from its superview’s view hierarchy.
As for the transitions, there are seven: animation options predefined
.transitionFlipFromLeft
.transitionFlipFromRight
.transitionFlipFromTop
.transitionFlipFromBottom
.transitionCurlUp
.transitionCurlDown
.transitionCrossDissolve
If you start to type UIView.transition
, the XCode autocomplete will give you a couple of options. There are two transition methods . The one we used previously animate a single view . There also a transition method between two views like if you wanted to flip a view around and see a different view on the other side
Let’s play around with this
As shown in Gif 10 , we used hidden = false
transition trigger but it is hidden without any animation, Why 😕
No matter which method or animation you choose , the views you want to effect should be wrapped in a separate container view or superview . The container view is the view you pass into the with
argument of the transition
As shown in Gif 10 since we gave the viewController as a container view, you can feel the transition effect animation throughout the whole view
As shown in Figure 13 we embedded our subview into a container view and now run thhe application you can see full smoth animation we want
Now we used transitionFlipFromLeft
animation option and triggering point is hide
and show
view
As we talked earlier there also a transition animation method that transitions between two views like if you want to flip a view around and see a different view on the other side . Let’s do it
As shown in Figure 15 , we created container view having two views as a subview, when user tap on toggle button, we will do the transition animation between two views
As shown in Gif 13 we used transition API with only with parameter and it is doing it’s works , there we used different animation option as well
As shown in Gif 14 We did the transition from the greenView
to purpleView and viceversa
. So we are going to have fromView
on the basis of toggle value for the from:
parameter and toView
for the to:
parameter. Let’s have the same 1 seconds for the duration:
parameter and let’s use a [.transitionFlipFromTop]
for the options:
parameter. Have the completion:
be nil
for now.
The first transition happens as expected, but when you click the button the second time, the compiler hits you with a ⚠ fatal error.
You may have noticed that this variation doesn’t have an animations:
closure like the other, and we need the animations:
closure to trigger the transition. Beacuse, this variation has some automated processes happening under the hood.
If you check your variables view at the bottom, you will notice that the toView
, which in this case is the greenView, is nil
.Here’s what happened: the automated transition trigger removed the greenView from the view hierarchy.
In the official Apple documentation, they state that, in this variation, the fromView:
is removed from its superview as part of the transition.
Well, that’s all fine, but we can’t just live with this fatal error.
As shown in Gif 15 in options:
parameter set,we added another option named .showHideTransitionViews
. What this does is simply hide the fromView
instead of removing it from the view hierarchy.
As shown in Gif 16 we added Button inside green View, and by default user can’t interact with views while they are being animated. means user can interact with textField at the bottom since it’s not taking part in animation but user can’t interact with button inside green view since it’s taking part in the animation.
By using allowUserInteraction
user can interact with views while they are being animated. In this case remember you can interact button when there is an transition between purple view to gree view not vice versa. so in short with allowUserInteraction
option you can interact with UI of the view which is going to appear not which is going.