Illustration by Kiran Puri

Animating your keyboard (part 2): reacting to WindowInset animations

Creating seamless keyboard animations using WindowInsetAnimation

Chris Banes
Android Developers
Published in
4 min readAug 24, 2020

--

In the previous blog post, we covered all of the changes to the APIs related to going edge-to-edge:

In this blog post we move forward on with the actual task of animating the keyboard. To demonstrate what is possible, here you can see an example of the same app, running on Android 10 on the left, and Android 11 on the right (at 20% speed):

On devices running Android 10 and before, when the user clicks on the text input to type a reply, the keyboard animates into place, but the app snaps between the states. This is the behaviour you’ve seen on your devices for a while, it’s just easier to see at 20% speed.

On the right you can see the same scenario running on Android 11. This time when the user clicks on the text input, the app moves with the keyboard, creating a more seamless experience.

So how can you add this experience to your app? Well it’s all powered by some new APIs…

WindowInsetsAnimation

The API which powers this in Android 11 is the new WindowInsetsAnimation class, which encapsulates an animation involving insets. Apps can listen to animation events through the WindowInsetsAnimation.Callback class, which can be set on a view:

So let’s just a look at the callback class, and the functions it provides:

Imagine that the keyboard is currently closed, and the user has just clicked on an EditText. The system is now about to start showing the keyboard, and since we have a WindowInsetsAnimation.Callback set, we’ll receive the following calls in order:

So that’s how the callback works in theory, now let’s apply it to a scenario…

Implementing the example

We’re going to use WindowInsetsAnimation.Callback to implement the example which you saw at the beginning of this blog post. So lets start implementing our callback:

onPrepare()

First we’ll override onPrepare(), and record the bottom coordinate of the view, before any layout changes have happened:

Insets dispatch

At this point, the end-state insets will be dispatched, and our OnApplyWindowInsetsListener called. Our listener updates the padding of the container view, which results in the content being pushed up.

The user never sees this though as we’ll see below.

onStart()

Next we have our onStart() function, which first allows us to record the end position of the view.

We also visually shift the view back down to its original position using translationY, as we don’t want the user to see the end state right now. The user doesn’t see a flicker, as the system guarantees that any layout triggered from the inset pass above is called in the same frame as onStart().

onProgress()

Finally we override onProgress() which allows us to update our view as the keyboard slides in.

We use translationY again, interpolating between the start and end states to move the view in unison with the keyboard.

Keyboard synergy

And with that, we have achieved synchronization between the keyboard and the app’s views. If you would like to see a fully implementation, check out the WindowInsetsAnimation sample:

Let us know on Twitter or the comments below if you add this to your app, and how you found it!

In the next blog post we will explore how your apps can control the keyboard, allowing things like list scrolling to automatically open the keyboard. Stay tuned!

View clipping

If you try and implement this in your own views you may find that the techniques we talked about in this blog post can lead to view’s being clipped as they are animated. This is because we are translating views which may have been resized through the layout changes from your OnApplyWindowInsetsListener.

We will explore in a future blog post how to combat this, but for now I recommend looking through the WindowInsetsAnimation sample, which contains one technique to avoid it.

--

--