A beginners guide to implement Android Animations — Part 1 (2 part series)
Admit it, you always wanted to create visually appealing apps. But due to functionality first approach, animations were always procrastinated. Not any more.
A little basics about animations:
There are 3 types of Animations:
- Property Animations — They are used to alter property of objects (Views or non view objects). We specify certain properties(like translateX, TextScaleX) of the objects to change. Various characteristics of animation which can be manipulated are animation duration, whether to reverse it and for how many times we want to repeat the animation etc. They were introduced in Android 3.0 (API level 11).
- View Animations — They are used to do simple animations like changing size, position, rotation, control transparency. They are easy to build and are very fast but have their own constraints. For eg — Their state changes but their property does not change. View animations will be covered in part 2.
- Drawable Animations — This is used to do animation using drawables. An XML file specifying various list of drawables is made which are run one by one just like a roll of a film. This is not much used so I won’t cover it.
Android 5.0 introduced various other animations — Reveal Effect, Activity/Fragment transitions, Shared Element transitions etc. Click here to learn more about this.
Note — Part 1 will discuss Property Animations only.
When to use which type of Animation
- If you just want to do simple animations on views without having to handle other details like touch or click, use View Animations. The problem with View Animations is that, though the View state changes, its property still remains at the original position. That means, if a ImageButton is moved from 0 to 100 pixels to the right, though it will animate to right, the touch(property) of image button will still be at 0th position.
- View Animations can be used in Splash screens. When using View Animations, use XML instead of doing it programmatically. Using XML files, it is more readable and can be shared among other views.
- If you want to handle touch, click after the animation, go for Property Animation as they change the state as well as behaviour.
Property Animation Concepts
The actual animation is done by Value Animator. This class keeps track of animation duration and the current value of the property that it is animating. TimeInterpolater keeps track about the time(speed) of animation like whether it is with constant speed in the given time, or accelerate then decelerate in the given time. TypeEvaluator is used to calculate fractions based on the type of TypeEvalutor used for eg, int, float, rgb etc. We can use a custom TypeEvaluator also if none matches our needs.
Animations Using ValueAnimator
The ValueAnimator
class lets you animate values of some type for the duration of an animation by specifying a set of int
, float
, or color values to animate through. You obtain a ValueAnimator
by calling one of its factory methods: ofInt()
, ofFloat()
, or ofObject()
. For example:
final TextView animateTextView = (TextView)findViewById(R.id.tv_animate);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 500f);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); // increase the speed first and then decreasevalueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float progress = (float) animation.getAnimatedValue();
animateTextView.setTranslationY(progress);
// no need to use invalidate() as it is already present in //the text view.
}
});valueAnimator.start();
The same thing can be achieved using XML code as follows:
/res/animator/value_animator_ex.xml<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:valueFrom="0f"
android:valueTo="500f"
android:valueType="floatType" /> ----Activity Code----ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(
this, R.animator.value_animator_ex);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float progress = (float) animation.getAnimatedValue();
animateTextView.setTranslationY(progress);
}
});
valueAnimator.start();
Animations Using ObjectAnimator
The ObjectAnimator
is a subclass of the ValueAnimator
and combines the timing engine and value computation of ValueAnimator
with the ability to animate a named property of a target object. This makes animating any object much easier, as you no longer need to implement the ValueAnimator.AnimatorUpdateListener
, because the animated property updates automatically. In most cases, we should use this.
For the same animation above, we can write the code for ObjectAnimator as:
TextView animateTextView = (TextView) findViewById(R.id.tv_animate);
ObjectAnimator textViewAnimator = ObjectAnimator.ofFloat(animateTextView, "translationY",0f,500f);
textViewAnimator.setDuration(2000);
textViewAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
textViewAnimator.start();
As we can see, we didn’t have to use listener to update position of text view as this is done by ObjectAnimator itself. The main thing here to see is “translationY” which is the property we want to perform animation on. This should be a defined property in android or if it is our own property then we must specify its accessor methods i.e. getter and setter method.
The same thing can be implemented using XML as:
/res/animator/object_animator_ex.xml<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000" android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="translationY"
android:valueFrom="0f"
android:valueTo="500f"
android:valueType="floatType" /> ----Activity Code----
TextView animateTextView = (TextView) findViewById(R.id.tv_animate);
ObjectAnimator textViewAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(AnimationActivity.this, R.animator.object_animator_ex);
textViewAnimator.setTarget(animateTextView);
textViewAnimator.start();
Doing Multiple Animations at a time
We can have multiple ObjectAnimators start at same time and for the same duration to do multiple animations, but it is not efficient as no view knows about any other view. To do the same we can use AnimatorSet class.
In my current project, I have done the following animation:
(Will be updated soon. Sorry for the inconvenience.)
As we can see, there are multiple animations running at the same time. There are 4 simultaneous animations going on. When the search icon is clicked, first the search icon is moving to the left, the logo is fading out, cancel button is fading in and edit text is also fading in. On clicking cancel button, the same animation is played but in reverse.
The code to do this is:
---------perform animation on search icon click ----------// take to leftmost position
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int modifierX = -(displayMetrics.widthPixels - v.getWidth()); private static final int SEARCH_ANIMATION_DURATION = 1000; // 1 secObjectAnimator searchIconLeftAnimation = ObjectAnimator.ofFloat(v, "translationX", modifierX);
searchIconLeftAnimation.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator logoFadeOutAnimator = ObjectAnimator.ofFloat(mAppLogo, "alpha", 1f, 0f);
logoFadeOutAnimator.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator cancelImageFadeInAnimator = ObjectAnimator.ofFloat(mIvCancelSearch, "alpha", 0f, 1f);
cancelImageFadeInAnimator.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator searchEditTextAnimator = ObjectAnimator.ofFloat(mEtSearch, "alpha", 0f, 1f);
searchEditTextAnimator.setDuration(SEARCH_ANIMATION_DURATION);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(searchIconLeftAnimation).with(logoFadeOutAnimator);
animatorSet.play(searchIconLeftAnimation).with(cancelImageFadeInAnimator);
animatorSet.play(searchIconLeftAnimation).with(searchEditTextAnimator);
animatorSet.start(); ---------reverse all the animations on cancel click ----------ObjectAnimator searchIconRightAnimation = ObjectAnimator.ofFloat(mIvSearch, "translationX", 0);
searchIconRightAnimation.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator logoFadeInAnimator = ObjectAnimator.ofFloat(mAppLogo, "alpha", 0f, 1f);
logoFadeInAnimator.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator cancelImageFadeOutAnimator = ObjectAnimator.ofFloat(mIvCancelSearch, "alpha", 1f, 0f);
cancelImageFadeOutAnimator.setDuration(SEARCH_ANIMATION_DURATION);
ObjectAnimator searchEditTextFadeInAnimator = ObjectAnimator.ofFloat(mEtSearch, "alpha", 1f, 0f);
searchEditTextFadeInAnimator.setDuration(SEARCH_ANIMATION_DURATION);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(searchIconRightAnimation).with(logoFadeInAnimator);
animatorSet.play(searchIconRightAnimation).with(cancelImageFadeOutAnimator);
animatorSet.play(searchIconRightAnimation).with(searchEditTextFadeInAnimator);
animatorSet.start();
Here we have created multiple Object Animators on different views and played them together using AnimatorSet. Methods like play() and with() helps to achieve this.
We can also use listeners to determine about the animation status. For eg:
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// do anything before animation start
}
@Override
public void onAnimationEnd(Animator animation) {
// do other stuff after animation ends
}
@Override
public void onAnimationCancel(Animator animation) {
// do something when animation is cancelled (by user/ developer)
}
@Override
public void onAnimationRepeat(Animator animation) {
// do something when animation is repeating
}
});
When performing multiple animations on a single view
Till now, we have seen animations on different view objects. We can perform multiple animations on a single view using the above approaches also (using animator set), but it is a performance overhead as there is the processing overhead of setting up the AnimatorSet and running two Animators in parallel. A better approach is to use ViewPropertyAnimator. Using this, the code is simpler to read also. For eg:
animateTextView.animate().rotation(360f).y(500f).setDuration(2000); ----------------------------VS-----------------------------
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(animateTextView, "rotation", 360f);
rotationAnimator.setDuration(2000);ObjectAnimator translateAnimator = ObjectAnimator.ofFloat(animateTextView, "translationY", 500f);
translateAnimator.setDuration(2000);AnimatorSet set = new AnimatorSet();
set.playTogether(rotationAnimator,translateAnimator);
set.start();
Does animation makes my app slow or will it surpass the 16ms draw window time? Is there any overhead on the performance ?
Animators that update the UI cause extra rendering work for every frame in which the animation runs. For this reason, using resource intensive animations can negatively impact the performance of your app.
Work required to animate your UI is added to the animation stage of the rendering pipeline. You can find out if your animations impact the performance of your app by enabling Profile GPU Rendering and monitoring the animation stage.
Think about the use case and then apply the appropriate way.
Thanks for reading the article. Suggestions/ Corrections/ Comments are always welcomed. If you like it, please hit the like button and share the article with the Android community. Let’s share the knowledge as much as we can.
Note — Part 2 on ViewAnimations is also coming very soon.
Also, Let’s become friends on About.me, Twitter, LinkedIn, Github and Facebook.