Custom Transitions in Android
Since Android API 19 Google provides a great feature — Transitions Framework. There are a lot of articles and videos about this framework, which describe why we need it, how to use it and so on. But today I want to talk about the custom transitions: why do we need it, how to implement it and some pitfalls I faced when was implementing my own custom transitions.
Why do we need the custom transitions?
Android SDK provides a set of the built-in transitions that developers can use in their apps(like ChangeBounds, Fade and so on). But there are at least two reasons why we need to implement the custom transitions:
- Implement transition for the view’s property that is not implemented in the built-in transitions.
- Implement transitions for the custom views.
For me the built-in and custom transitions become more and more interesting because they can be used for the shared elements transitions, which is the awesome part of the modern Android UI.
Implementation of the custom transition
To implement a custom transition we just need to extend Transition class and implement three methods: captureStartValues, captureEndValues and createAnimator (for more details about the implementation of the custom transitions you can check this page).
In the captureStartValues and captureEndValues methods we need to capture all the view’s property values that will be needed to create an animation. One of the most important things in this methods is to use the naming scheme “package_name:transition_name:property_name” for the keys in the TransitionValues map as described here.
In the createAnimator method we need to create an Animator object(or a set of the animators) for animating the view’s properties using the captured values.
Here are two important things:
- if we don’t add a constructor(even empty) with the parameters (Context, AttributeSet) — an exception “java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]” will be thrown when we will use a custom Transition for the shared elements transition;
- if we don’t put values into the TransitionValues at all or put the same values in the methods captureStartValues and captureEndValues — the createAnimator method will not be called and the animation will not happen.
I think that’s enough for the theory and let’s start to write the code. For this article I’ve implemented two custom transitions. One animates the change of the TextView’s text color. And the other animates the change of an inner radius, an outer radius and a color of the custom view RingView. All the source code for this article you can find here.
TextColorTransition
As I’ve already said TextColorTransition animates a change of the TextView’s text color:
I think the code is self-explanatory: it captures the start and the end text’s color values and then creates an animator to animate the change. To use this transition we need to call TransitionManager.beginDelayedTransition and then change the TextView’s text color :
And now the TextView’s text color will be changed smoothly.
The implementation of the RingViewTransition is almost the same — it captures three custom RingView’s properties and creates a set of the Animators for the captured values in the createAnimator method.
Shared elements transition
It is time to talk about the shared elements transition. We can use implemented transitions to animate the changes of the shared elements. Assume we want to implement the next activity transition:
To do that we need to describe transitions in the res/transition/ folder and using android:windowSharedElementEnterTransition and android:windowSharedElementReenterTransition attributes apply this transitions for the shared elements in the style. In my case enter and exit transitions are the same:
We use TextColorTransition and RingViewTransition to animate the text color change and the RingView’s properties change. Also we’ve added the AutoTransition to animate all the other stuff. Now we can run the app and see the result:
The transition doesn’t look like we wanted. The reason why the transition doesn’t work is because captureStartValues and captureEndValues are called on the destination activity and both methods capture the final values of the needed properties. And that’s why the animation doesn’t happen and createAnimator method is not even called. To fix this issue we need to capture the needed properties in the source activity “manually”:
We put the Bundles with the captured values to the extra using the transition names of each shared element. In the destination activity we’ll get the Bundle from the extra by transition name and put it to the tag of the corresponding view. All this stuff should be done before the shared elements transition starts, so the best place to do that is onSharedElementStart callback. It is also important to reset tags in onSharedElementEnd callback or otherwise the transitions will use values from the Bundle as a start and end values:
And now we need to modify TextColorTransition and RingViewTransition a little to make them use values from the tags:
This is the final implementation of the TextColorTransition and RingViewTransition. Now we can start the application and all the shared elements transitions work as desired.
Support Transitions
Recently Google released support library with the support version of Transitions(back to API 14). If you want to use Transitions only with the TransitionManager.beginDelayedTransition then you can use them. The implementation will be the same. The only difference is you need to extend support Transition class. But if you want to use Transitions for the shared elements — then you can use only the native Transitions.
Conclusion
Transitions is a very great tool. And it can be used for a different stuff. But to be able to use it you need to spend some time and learn how to deal with it. And when you will know how it works in general and how to implement your own Transitions — you will be able to do amazing UI.
I also encourage you to look this and this videos about Transitions.
Looking forward for your feedback and feel free to ask the questions.