Animations and effects are important elements/aspects of modern mobile apps. Each app has dozens of similar apps available in the stores/gallery; you need to make yours stand out so customers will download yours. Beautiful animated UI helps it stand out.
Moving UIView from one point to another, (e.g., when the keyboard appears/disappears)
Animating properties like color or transparency
Parallax effect with UIScrollView, UITableView, or UICollectionView
“Hero” animation – moving the item from one view to another
Overriding default transition between UIViewControllers
Animating Views
Animating own properties of views, like color, transparency, or scale
Animating layout by changing constraints
Animating UIView’s Own Properties
The most popular animation of UIView is “fade”. “Fade in” makes UIView appear; “fade out” makes it disappear. What is appearing and disappearing? It’s changing alpha property from 0.0 to 1.0 and back. Why do we change alpha instead of isHidden? It’s a Boolean value. Boolean values cannot gradually change. They’re always either true or false. Will this animation work anyway? Well, try it as an exercise. We’ll stick to alpha here, as it’s a gradually changeable property.
Animation can be done using UIView type animation (withDuration:animations:). It’s a type method, so you call it directly on type UIView, not on instance.
Fade-in Effect
Before performing an animation, we set initial parameters. It’s not compulsory, especially if you want to animate it from its current state. Adjust it for your needs.
You can also see a magic number in this recipe – 0.3. Magic numbers are unnamed numeric constants. It’s a bad practice because the developer working on this code after you (or even you in several months or years) may not understand why this constant is there and what it means.
We’re talking about animation, and this code is part of the book, so it’s acceptable to give an explanation here. 0.3 seconds is a common time interval for animations. It’s slow enough to let the user see it, but fast enough not to delay them.
If you use this code, adjust this time interval for your needs and define a named constant for it.
Fade-Out Effect
Frame
Bounds
Center
Transform
Alpha
BackgroundColor
Subclasses of UIView may have other properties to animate; you can refer to documentation to see a full list for each class.
Animating Layout by Changing Constraints
When iPhone just appeared , it had only one resolution. Later, when new models appeared, screen became taller. On iPad, the opposite, it became wider. Now we have many aspect ratios. The way to survive in all this variety is to use constraints. If you’re reading this, you probably already know what are constraints. If not, you can always find documentation, books, articles, or tutorials explaining how they work.
If you have constraints, you shouldn’t animate frame and other position-related properties. You should animate changes in constraints.
Up to the present day, constraints are objects of class NSLayoutConstraint; it starts with NS, and it doesn’t have an alternative.
Animating Constraints
Restrictions
Animations in iOS have their own restrictions . We already discussed that you can’t animate values that can’t be gradually changed.
Another restriction is simultaneous animations. You can animate several properties or different objects at the same time, but they must be wrapped into the same block.
Split them into small blocks, each of them with a set of changes ending at the same moment. When one block ends, start the next block. It may need some calculating.
Make a timer to animate manually. The UIView.animate(withDuration:animations☺ method is not the only way.
Animating Layout When Keyboard Appears
Animating Layout Changes When Keyboard Appears
Parallax Effect
Parallax effect in general is creating several layers moving with different speeds. This effect is often used in 2D platformer games or runners. Clouds behind the player move much slower than the player themselves. At the same time, the front layer covering the character moves faster.
In mobile apps, the parallax effect is often used as a screen header when content is scrollable. It can be a food ordering app, showing the restaurant photo above the menu. When the user scrolls the menu, the header should become smaller, leaving the back button and restaurant name, possibly with the restaurant logo or a card icon.
Parallax Header with UIScrollView
A big part of this feature is the user interface, so let’s prepare it first.
Preparing User Interface
UIImageView on the background. Content mode should be set to Aspect Fill. This way, the background image will scale automatically, leaving only part of the picture visible, but it will always fill the whole screen.
UIView shading. Background color will be black, but transparency (alpha) will change from 0.3 to 0.8.
UIButton will be a static back button, always located in the top-left corner of the header.
UILabel will display a title. Large and centered when the header is expanded and small when the header is shrunk.
When the user scrolls UIScrollView, the header will change height from 180 to 40. Scrolling back will reverse the process. In the full version of code, all numbers will be declared as constants.
The UIScrollView object should be located behind the header; otherwise, it will overlap the entire header. At the same time, we can’t put it below. This needs a detailed explanation.
If our scrollable area is located below the header, its position and size will change every time the header height is changed. As the user’s finger won’t move, it will change its position in a scrollable area system of coordinates. It may look good, but usually it creates undesired shaking of scrolling offset.
Finally, we need to add some content to the scrollable area. Don’t forget that it must have the margin from the top border, at least 180; otherwise, it will be hidden behind the header. If you want to scroll the bar, you should also add an inset in the Indicator Insets section in the storyboard editor. If not, hide it.
shadeView.alpha is 0.3.
titleLabel.font is UIFont.systemFont(ofSize: 32).
headerHeightConstraint.constaint is 180.
titleLeadingConstraint.constaint is 16.
If the layout is too complicated, and you can’t build it using this instruction, you can find an example in the GitHub repository .
Parallax Functionality
To calculate all the values, we need to know current progress, which is a value from 0.0 to 1.0, where 0.0 is fully expanded and 1.0 is fully shrunk. How do we calculate shrink progress from scrollPosition?
Parallax Effect
To make sure all our values stay in range, we clamp progress, limiting its values from 0.0 to 1.0 in the first line.
Parallax Header with UITableView and UICollectionView
Having code for parallax effect with UIScrollView, we can easily make parallax effect with UITableView or UICollectionView. The thing is that both of these views are subclasses of UIScrollView, so when you set a delegate, it automatically sets UIScrollViewDelegate.
Still, we need to make some changes both in the code and in the storyboard.
First, change UIScrollView to UITableView. Add indicator inset like you did before and create a cell prototype to make some demo content. In the following recipe, it’s just one UILabel with tag property equal to 1.
Parallax Effect with UITableView
Similarly, you can do it for UICollectionView.
Feel free to customize header effects. Add more elements; make movements nonlinear or whatever comes to mind.
Hero Animation
Hero Animation Within the Same UIViewController
Create and hide UIView in its destination point.
Calculate the difference in position and size between source and destination points.
Apply transformation to this UIView to make it look exactly like source UIView.
Hide source UIView and show destination UIView.
Animate destination UIView to return it to destination.
Translation – Difference in position
Scale – Difference in size
Let’s build the entire algorithm, step by step; then wrap it up in a recipe.
Create and Show UIView
Hero animation is always the movement of an element , which looks the same but becomes larger. Original (source) UIView is smaller, so upscaling it will lead to quality loss. We need to create another UIView. Possibly, it’s already created. In this case, we need to set it up. If you choose audio tracks with thumbnails, and the user selects one, you need to apply image and track name to the destination UIView.
If you create it, make it hidden. If you have it in storyboard, it must be marked as hidden there.
Calculate Transformation
Apply Transformation
Hide Source UIView and Show Destination UIView
Animate
That’s it! Your hero can be a simple UIImage or a complex layout inside UIView.
Final Code
Hero Animation
Also, we use another UIView – targetView. It’s an invisible instance of UIView, allowing us to set the geometry of destination in a storyboard.
Hero Flying to a New UIViewController
The difference between animation within the same UIViewController and two different UIViewControllers is that we can’t use destination UIView from a storyboard.
Run a segue or push destination UIViewController. Hide destination UIView on start.
Create a transition UIView matching destination UIView.
Calculate source and destination positions and scales.
Add transition UIView to UIWindow and apply the source transformation.
Hide source UIView.
Apply animation of transition UIView’s transformation. Transition between screens; the animation of UIView should be synchronous.
When the animation ends, hide the transition UIView and show the destination UIView.
Show the source UIView to make it visible when the user goes back.
Hero Animation Between Screens
Getting and Using UIWindow
In this recipe, we assume that the project uses Scenes. currentWindow computed property is defined in Recipe 4-3. If you don’t use Scenes in your project, use Recipe 4-4 instead.
It may sound strange, but UIWindow is a subclass of UIView. That means we can use any UIView method on UIWindow. This includes addSubview and converse.
Details
Several more explanations to make it clear.
The rest of the code is basically the same as in the previous section with minor adjustments.
Transition Between Screens
Appearing from right to left inside UINavigationController
Appearing from bottom to top when you present a modal UIViewController
You can change animation in the “storyboard editor” or in code, but there’s very limited choice. Luckily, iOS allows us to create a custom transition animation.
Standard Transitions
If it happens inside UINavigationController, there is only one animation. The second screen covers the first one from the right side (or left side for right-to-left languages).
When you present new UIViewController modally, there are several default options. We can choose the animation type in storyboard or in code before presenting.
If you use storyboards and segues, you need to choose the type of segue (Show for pushing and Present Modally for... presenting modally). Others are also used, but less often, and they have less customization options, so we’ll set them aside for now.
Presentation defines how the result looks. By default, it covers about 90% of the screen, leaving a piece of the previous screen on top.
Transition defines the effect.
Changing Presentation and Transition
Creating a Custom Transition
If you’re not happy with standard animation, you can create your own custom transition.
UIViewControllerTransitioningDelegate is a protocol you need to implement to make custom transitions. Implementation of this protocol defines animation and interaction controllers for presenting and dismissing.
Implementation of the UIViewControllerAnimatedTransitioning protocol defines the duration of transitions and the transitions themselves and handles some callbacks.
UIViewControllerContextTransitioning is a context. Implementation provides information about transitioning views and controllers.
- 1.
When you trigger transition (using segue or manually), iOS checks if transitioningDelegate is set. If no, it uses one standard transition, the one you set or the default one.
- 2.
If transitioningDelegate is set, it calls animationController(forPresented:presenting:source) of your transitioningDelegate. This function is optional; it’s valid to return nil. If it does, the transition will be standard, like if transitioningDelegate wasn’t set.
- 3.
At this point, iOS concludes that custom animation must be used and creates a context.
- 4.
transitionDuration(using:) is called to define transition time. Time should return in seconds. Usually, it’s around 0.3 seconds. Transitions longer than one second will probably be uncomfortable for users.
- 5.
Next, animateTransition(using:) is called. With this method, you can apply animations. Having context (in using argument), you can apply any modifications to both screens. You can change colors, positions, transparency – whatever you like.
- 6.
Finally, you need to call completeTransition(_:). This will mark transitions as over and make the destination view controller live. If you don’t call it, it will remain inactive .
Fade Through Black Transition
This code includes backward transition, identical to the forward one.
Transition Libraries
The Hero ( https://github.com/HeroTransitions/Hero ) library offers an easy way to apply one of the predefined transitions with a good set of tools for customizations.
The Jelly ( https://github.com/SebastianBoldt/Jelly ) library also allows interactive transitions.
Shift ( https://github.com/wickwirew/Shift ) is an animation library for hero-like transitions. With relatively little effort, it makes beautiful animations.
All these libraries are free, open source, and available via the Swift Package Manager and CocoaPods. You can use them free of charge in your apps, but don’t forget to donate if you like them.
Summary
Modern mobile apps should use animations to look more user-friendly. UIKit offers native solutions for simple UI animations. In this chapter we discussed fade animations and animated layout changes. We talked about popular in mobile apps parallax effect, hero animation as a part of transition between screens. Finally, we reviewed different ways of transition itself. This wraps up UIKit topic, but UIKit is not the only way to create UI in iOS apps. Since iOS 13 Apple introduces SwiftUI, which is already actively used in both iOS and macOS UI development. In the next chapter we’ll have a fast look at SwiftUI.