Create transition animations between Activity in Android

Starting with Android 4.4, an additional tool for creating animations appeared in the arsenal of developers - the Transitions Framework. Initially, it was intended to create animations of changing the state of an application by manipulating several View. With the release of Android 5.0, the range of animations available for use has been expanded to match the then presented Material Design concept.

Transitions Framework allows you to quickly and painlessly create various animations. Therefore, in the process of working on iFunny it was impossible to get past this toolkit. Readers are offered a special case of using the Transitions API - creating an animation of the transition between Activity with a seamless effect.

image

From a visual point of view, the animations of transitions between Activity presented in the Transitions Framework can be divided into two types: ordinary animations and animations with a common element. The concept of an animation with a common element is shown in the honestly stolen from developer.android.com website pic. 1. On it in the role of common elements are the avatar and name of the contact.

image

Fig. 1. Animation of the transition between Activity with common elements
But no one likes long intros, so let's move on to the story of how this type of animation was created in the iFunny application. As a first example, consider the animation shown in fig. 2. To use it, we need Android version 5.0 and higher.

image

Fig. 2. Animation of the transition between Activity on the user authentication screen
From the user's
point of view, there is nothing unusual here: one screen, a simple animation. But, as you might have guessed, “under the hood” is a transition between two screens with one common element.

The first step to creating such a transition is, oddly enough, choosing this very element and determining its location in the layout of both Activity. After that, in the description of each View that displays the selected item, you need to add the attribute android: transitionName, and also assign them android: id, if one is missing.

In our case, these are ordinary ImageViews of the following form:

<ImageView
     android:layout_width="40dp"
     android:layout_height="40dp"
     android:layout_gravity="center"
     android:transitionName="@string/email_auth_transition"
     app:srcCompat="@drawable/ic_ifunny_logo"
     />

Two important points should be noted here. Firstly, in both ImageView it is necessary to set the same transitionName, which is logical. Secondly, as long as we use ImageView, their content should be the same, because using two different resources can lead to unexpected consequences (at least to blink the animated View at the beginning and end of the animation).

At the second step, you need to add options for the launched (second) Activity, informing that the animation should be started when it starts.

Note. By “second” is meant a triggered Activity, the transition to which must be made, and by “first” is a starting Activity.

This is done as follows:

Bundle bundle = null;

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
  View v = activity.findViewById(R.id.auth_logo);
  if (v != null) {
     ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, v, activity.getString(R.string.email_auth_transition));
     bundle = options.toBundle();
  }
}

Intent intent = new Intent(activity, SecondActivity.class);
if (bundle == null) {
  activity.startActivity(intent);
} else {
  activity.startActivity(intent, bundle);
}

In the listing above:

  • R.id.auth_logo - ImageView from the first Activity used in the animation;
  • activity - the first Activity;
  • R.string.email_auth_transition - label previously left in the layout of both ImageViews;
  • SecondActivity.class - the second Activity.

And now the attentive reader may be perplexed: the introduction dealt with the use of API level 19, the example featured API level 21, and in the listing above there is a restriction on API level 22. Unfortunately, when writing the code, it turned out that transition animations with a common element may behave incorrectly on phones with API level 21. This is manifested in the form of slowdowns of the animation in general and artifacts on the animated View in particular. If you are already familiar with the topic, know the reasons for this behavior and / or ways to solve the described problem - tell us about it in the comments.

In the third step, it is necessary to describe the transition animation, i.e. specify the path followed by the animated View, and the transformation of the View itself. To do this, create a separate projectName / src / main / res / transitions / email_auth_transition.xml file with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet
		xmlns:android="http://schemas.android.com/apk/res/android"
		android:transitionOrdering="together">
	<changeBounds/>
	<changeImageTransform/>
</transitionSet>

A bit of theory. The transitionSet tag is intended to describe several transformations applied to the animated View at once. The transitionOrdering parameter is responsible for the order in which these transformations are applied. In our case, they are used simultaneously. There are several types of off-the-shelf transformations presented in the Transitions Framework. A complete list is available on this page . We will focus on two specific ones: changeBounds and changeImageTransform.

The first is for transforming View size. The second only works with ImageView and in conjunction with the first allows you to change not only the size, but also the shape of the ImageView. Using the transformation data, we get the output of the image resizing animation shown in Fig. 2. If you do not specify the type of motion of the animated View, then it will move along the shortest path. We consider a more interesting way of transportation in the second example.

The last step in creating an animation is to declare it in the themes of both Activity. To do this, edit the description of the topic as follows (or create new ones in the projectName / src / main / res / values-v22 / theme.xml folder):

<style name="Theme.FirstActivity" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowActivityTransitions">true</item>
</style>

<style name="Theme.SecondActivity" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowActivityTransitions">true</item>
        
        <item name="android:windowSharedElementEnterTransition"> 
                @transition/email_auth_transition 
        </item>

        <item name="android:windowSharedElementExitTransition"> 
                @transition/email_auth_transition 
        </item>
</style>

Here:

  • android: windowActivityTransitions enables transition animations;
  • android: windowSharedElementEnterTransition points to a file with a description of the animation of the transition from the first Activity to the second;
  • android: windowSharedElementExitTransition points to a file with a description of the transition animation when returning from the second Activity to the first.

It should be noted that for OS versions lower than 5.1, it is necessary to create themes with identical styles in order to avoid the expected consequences in the form of an application crash. For example, put them in the file projectName / src / main / res / values ​​/ theme.xml:

<style name="Theme.FirstActivity" parent="Theme.NoActionBar.Translucent"/>
<style name="Theme.SecondActivity" parent="Theme.TransparentActionBar"/>

So, to create an animation of the transition from Activity to Activity, you need:

  1. Describe animations (in our case, in an xml file);
  2. Add these animations to the xml description of the Activity theme;
  3. Mark animated common element (View) in the markup;
  4. When starting the second Activity, specify in the launch parameters that it is necessary to use transition animation for it.

As you can see, creating such animations is not at all difficult, except for some of the limitations mentioned in the first example. Now consider a second, more complex example. Here we are interested in going from the comments section to the user profile (Fig. 3).

image

Fig. 3. Transition animation from comments to the user profile
All the steps for creating a transition discussed above are also suitable for this animation. But the transformation of the common element is implemented a little differently. The listing below describes the movement of a common “arc” element along with a change in its size.

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">

    <changeBounds>
        <arcMotion
            android:maximumAngle="90"
            android:minimumHorizontalAngle="90"
            android:minimumVerticalAngle="0" />
    </changeBounds>

</transitionSet>

What is the complexity of the second example? In the first case, the image from the resources of the application itself was used, and here - the picture is downloaded from the network. In addition, for comments, the image of the user's avatar is taken in a lower resolution than for the profile. Therefore, it is required not only to give the second Activity access to the image used in the first, but also to load the required image in higher quality at the end of the animation. So it turns out two problems.

To solve the first one, one could personally cache the image to disk or transfer its address in the parameter of the second Activity. However, the solution to this problem was transferred to the library used to download images used in the application - Glide. When loading an image, just add the diskCacheStrategy parameter (DiskCacheStrategy.SOURCE) and it will be cached by the library itself (relevant for Glide version 3.x). Therefore, when accessing this resource again from the second Activity, a cached file will be used, which will help us avoid blinking of the animated ImageView.

The second problem is also solved quite simply. While the transition is being animated, the user profile, along with a higher-resolution avatar, are downloaded from the network and await its completion. As soon as both conditions are met (completion of the animation and completion of the download), the user's avatar is updated. This behavior can be achieved if you use a special Listener, which implements callbacks that are called when the animation status changes. To do this, in Fragment, which belongs to the second Activity, set this very Listener:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  super.onViewCreated(view, savedInstanceState);
  if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
    getActivity().getWindow().getSharedElementEnterTransition()
      .addListener(mEnterTransitionListener);
  }

  setAvatar();
}

Here the following happens:

  1. Using getSharedElementEnterTransition (). AddListener () sets the Listener to animate the appearance of the Activity;
  2. В методе setAvatar() производится попытка загрузки и установк and avatar. (который уже лежит в кэше).

Consider exactly how Listener is implemented:

private Transition.TransitionListener mEnterTransitionListener = 
      new Transition.TransitionListener() {
  @Override
  public void onTransitionStart(Transition transition) {
  }

  @Override
  public void onTransitionEnd(Transition transition) {    
        onProfileUpdated();
  }

  @Override
  public void onTransitionCancel(Transition transition) {
  }

  @Override
  public void onTransitionPause(Transition transition) {
  }

  @Override
  public void onTransitionResume(Transition transition) {
  }
};

In the onProfileUpdated () method, we update the contents of the profile, including and avatar.

It is worth mentioning separately the case when a common element goes beyond the screen. Its peculiarity lies in the fact that, contrary to (or maybe according to) logic, the transition animation will still be performed and will look quite funny (Fig. 4).

image

Fig. 4. Animation of returning from a profile in a comment
To avoid such behavior, it is enough to set the visibility different from View.VISIBLE when the general element leaves the screen.

In general, we can say that the Transitions Framework is a simple and powerful tool for creating animations. It is not limited only to animations of the transition between Activity - the article examined only a special case of its use. It is also worth noting that in addition to the provided transformations, it is possible to create your own, but this is a completely different story, worthy of a separate post.

P.S. А о том, как придумывались анимации для iFunny, вы можете прочитать тут .