Changing text size and color in Shared Element Activity Transition

Animating the textSize property is an easy solution but, not the correct one. Yes, if you want to perform an Activity transition while changing text size and color, you can probably change the text size and color properties directly as shown by Alex Lockwood here. While this works, and serves as a great example of how to create custom transitions, this also thrashes your font cache. Don’t take my word for it here is a video from Google I/O where that exact sentiment is echoed. If you want to learn how to animate text size, that video is a great starting point, it explains the general concept, and also provides some code. The relevant part should start at 14:35 mark, that’s where they talk about creating custom animations and use animating text size as an example. At about 16:20, they mention why you shouldn’t just change the text size attribute. Animating font size will thrash your font cache!

What is font cache and why should I worry about thrashing it?

This is a question I’m not fully qualified to answer. This is a topic that I don’t fully understand. The short answer is, other than taking up memory for various font sizes, this can affect the speed at which text is rendered in your app. If you’re an OpenGL developer this may make intuitive sense to you, if you want to read more on this topic, there is a great post by Romain Guy on how android renders fonts here.

I will admit that this is a common mistake. I have come across a lot of code that animates text size. I even have various open source widgets that animate text size and they are all being re-written because I’ve made the mistake of animating text size instead of converting text to a bitmap and animating the bitmaps.

So, I understand the concept, but how do I implement it?

I’ve written custom transitions before, but even as such, there is not enough in the video to give me an idea of how to do a great job of writing the code that animates text size and color (and some other properties), well. Luckily you don’t have to write this yourself! Nick Butcher has done a lot of the heavy lifting for us in Plaid. The best way to up your game as a developer is to read code by other developers!

Now, I know all of you are really busy, so I’ve taken the time to quickly outline what you need from Plaid to create your own text size, color etc Activity transition animation. In order to get started, you’ll need the following classes/files:

  • ReflowText — There is a lot in this class. It contains other sub-classes all of which are very important.
  • FontUtil — You can leave this class out, caching fonts is important for various reasons, but if you don’t need this, I’ll show you where to remove it from ReflowText or how to customise it to suit your project.
  • attrs_reflow_text.xml — ReflowText is a custom animation that can be defined in XML, it has custom properties which are defined in this file. There is a bug in this file, I’ll provide more detail below on how to resolve it.
  • ids.xml — There is just 1 id defined in there, that’s what you need, you can take the whole file or just copy that one line in to your ids.xml file.

There are more files (such as the transitions xml files), however, there is a lot going on in them and it may just be easier to define our own transition animation. If you drop all those files in to your project, you will (hopefully) have no errors.

Bug in attrs_reflow_text.xml

The project, for me, does not compile unless I modify this file a little. In the master branch velocity, minDuration and maxDuration do not have format specified. If you have the same issue, update these as follows:

<resources>

<declare-styleable name="ReflowText">
<attr name="velocity" format="dimension" />
<attr name="minDuration" format="integer" />
<attr name="maxDuration" format="integer" />
<attr name="staggerDelay" format="integer" />
<attr name="freezeFrame" format="boolean" />
</declare-styleable>

</resources>

Handling custom fonts

ReflowText handles custom fonts for you, however, you have to tell it which custom font you are using. In the project that I link below, I use Calligraphy and only have the one custom font. However, if you have multiple custom fonts you’ll have to figure out how to specify in the TextView which custom font is being used.

You can use FontTextView from Plaid and specify your custom font that way, or you can use Calligraphy. If you use Calligraphy, it’s up to you to find a way to pass font information around. You’ll need to make changes in 2 places ReflowText$ReflowableTextView.getFontName() and ReflowText.createLayout() roughly line 448. My advice if you use Calligraphy is to pass this information in tag.

Our custom transition

We can get away with using only enter animation, however, I’ll provide both enter and exit animation files below as this produces a smoother experience.
The files below go in app/main/res/transition

<!-- reflow_enter.xml -->
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:transitionOrdering="together">
<transitionSet android:interpolator="@android:interpolator/fast_out_slow_in">
<targets>
<target android:targetId="@id/txt_main" />
</targets>
<transition
class="io.plaidapp.ui.transitions.ReflowText"
app:maxDuration="3000"
app:minDuration="200"
app:staggerDelay="30"
app:velocity="700dp">
<arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="90"
android:minimumVerticalAngle="0" />
</transition>
</transitionSet>
</transitionSet>
<!-- reflow_exit.xml -->
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:transitionOrdering="together">
<transitionSet android:interpolator="@android:interpolator/fast_out_slow_in">
<targets>
<target android:targetId="@id/txt_main" />
</targets>
<transition
class="io.plaidapp.ui.transitions.ReflowText"
app:velocity="1000dp"
app:minDuration="230"
app:maxDuration="230"
app:staggerDelay="10"
app:freezeFrame="true">
<arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="90"
android:minimumVerticalAngle="0" />
</transition>
</transitionSet>
</transitionSet>

Note 1: I kept classes from Plaid in their original package structure because I don’t know what the “licensing” implications of using these classes is, so, credit is still with plaid.

Note 2: Specifying targetId is optional if you don’t specify targetId, the transition will be applied to all views that are being animated.

Using ReflowText class

With all of the above setup. We are ready to animate our text. In order to do this, we have a few steps.

First, before we launch an activity, we have to capture information about our TextView. We do this like so:

@Override
public void onClick(View view) {
Intent intent = new Intent(this, Main2Activity.class);
ReflowText.addExtras(
intent,
new ReflowText.ReflowableTextView((TextView) view));

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, view, "hello_world");
startActivity(intent, options.toBundle());
}

Secondly, in the new activity, we map our views to the data captured.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
final TextView textView =
(TextView) findViewById(R.id.txt_main);
textView.setTransitionName("hello_world");
//can set this in the xml layout as well.

setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onSharedElementStart(
List<String> sharedElementNames,
List<View> sharedElements,
List<View> sharedElementSnapshots) {
ReflowText.setupReflow(getIntent(), textView);
}

@Override
public void onSharedElementEnd(
List<String> sharedElementNames,
List<View> sharedElements,
List<View> sharedElementSnapshots) {
ReflowText.setupReflow(
new ReflowText.ReflowableTextView(textView));
}
});

}

Thats it!

If you run your project now, your text should animate smoothly!

Sample Project

Demo

Finally

In order to build great Android apps, read more of my articles.


Yay! you made it to the end! We should hang out! feel free to follow me on Medium, LinkedIn, Google+ or Twitter.