UIView Interactive Animations

Written by MPow on Aug 18, 2014

This is the first of three blog post talking about Interactive Transitions and Animations with UIKit; I will start with UIScrollView and gesture driven animations today, UIViewController and UICollectionView Transitions later.

A good UX is necessary to build an awesome and usable Application; Interactive Transitions and Animations, other than good looking, could help your App to be more intuitive for Users.

Drive an Animation

Build a Driven Animation is a bit different that animate an object using CoreAnimation. The easiest way to animate a view looks like this:

[UIViewanimateWithDuration:.2animations:^{myView.alpha=0;}];

You can do that after a button is pressed or a cell is tapped, it will fade out the view in 0.2 seconds but there is no way to fully control it.
You can adjust the timing of an animation using CoreAnimation but is still not driven by an user action; in the same moment you start that animation is already known what will happens and when it will finish.
To build interactive Animations we need to define the behaviors of an Object not depending by the time, usually is used the Percentage of completion of the Animation.

Percentage

What we need to drive the animation is a float between 0.0 and 1.02, as it represent 0% to 100% we can call it percentage.
Since we are talking about Interactive Animations we will need to get the percentage of completion from an user interaction.
I will talk about the most used (by myself): UIGestureRecognizer, UIScrollView’s scroll.
There would be a third one but since is based on UICollectionViewLayout will be in the last episode.

rotation and scale return a float, translationInView: locationInView: returns a CGPoint so you can choose x or y based on the kind of animation you need to build.
I will explain you how to normalize any of these values using UIScrollView’s contentOffset.

UIScrollView

UIScrollView can drive animations as well as gesture recognizers, we will use the contentOffset captured through the ScrollView Delegate scrollViewDidScroll:.
As soon as the user scrolls the delegate will be called and we will get the offset; we need to normalize the value in order to get a percentage.
An easy way is to define wich one will be the maximum offset and calculate the percentage through it. For example:

-(void)scrollViewDidScroll:(UIScrollView*)scrollView{CGFloatoffset=scrollView.contentOffset.y;CGFloatpercentage=offset/250;CGFloatvalue=250*percentage;// negative when scrolling down after the top
}

When the scrollView is at the top:

When you scroll up more than the top:

When you scroll down:

Now that you have a percentage value you can do your driven animation.

Example

An example is the popular Parallax3 effect on a UIScrollView4.
Assuming that we have an UIImageView inside our UIScrollView we want to increment the height of the ImageView height when we scroll up after the top, and decrement it to have a Parallax effect while scrolling down. We just have to play with IMAGE_HEIGHT and the offset.

-(void)scrollViewDidScroll:(UIScrollView*)scrollView{CGFloatoffset=scrollView.contentOffset.y;CGFloatpercentage=offset/IMAGE_HEIGHT;CGFloatvalue=IMAGE_HEIGHT*percentage;// negative when scrolling up more than the top
// driven animation
imageView.frame=CGRectMake(0,value,scrollView.bounds.size.width,IMAGE_HEIGHT-value);// if scrolling down after the top
// y become negative
// height = original heigh minus a negative value, so: bigger
}

Modifiers

We can even play with our percentage for different effects. For example if we want to animate the alpha of the label, in this case, we can’t use the percentage directly; using label.alpha=percentage; we would have a transparent label when the scollview is at top instead of a value==1, and close to 0 when we scroll. What we want is the exact opposite so we can do:

CGFloatalphaValue=1-fabs(percentage);label.alpha=alphaValue;

We want even the label to quickly disappear when not needed (not near to contentOffset.y==0) so we can use a cubic funcion

label.alpha=pow(alphaValue,3);//alphaValue*alphaValue*alphaValue;

That was just an example, manipulate your values to build your animation properly, you can even use a sine wave if you like!
Last thing: be careful to the bounds of your animations, to not waste resources; in my project even after the image is not visible I continue to calculate all I need while I should control if it’s needed or not.