Back in November 2012, I wrote a blog post entitled “ActionBar on the Move”. This article was mainly dealing with a technique to nicely and uniquely animate your
ActionBar. Although I mentioned some of the effect’s possible applications, I never had time to effectively add an
ActionBar animation to one of my own apps nor saw an application on the Play Store taking advantage of it.
While being at Google I/O last week, I finally found an application using the
ActionBar animation technique. Let’s be honest, it literally blew my mind the first time I saw it. I felt in love with the nice, subtle and yet extremely useful animated effect probably more than the entire app itself! I am pretty sure you know the application I am talking about as it has been presented during the Google I/O keynote. You have also probably recently received an update of it: Play Music!
The latest update of Play Music (v5.0) has been completely redesign and features a brand new artist/album detail screen. If you open such a detail screen, you’ll notice the
ActionBar is initially invisible and overlaps a large image describing the artist/album. Once you start scrolling down (if possible), the
ActionBar fades in gradually. The
ActionBar turns completely opaque when the large image has been scrolled out of the screen.
Here are two main advantages of this
Polish the UI: animations synchronized on an element you’re interacting with are generally appreciated by users because it makes them feel the UI is natural and reacts to their actions. The fading animation is a direct consequence of the per-pixel scrolling state and not a launched-once animation.
Take advantage of the screen real estate: while still preserving the UX of the platform, this pattern let the user primarily focus on the content rather than the controls. Used in addition to a nicely designed screen, it can be a game changer for your app’s interface.
In this article, I will deep dive into the details of implementing the technique described in “ActionBar on the Move” to create an effect similar to the one used in the Play Music app.
In order to better understand the goal we are targeting, you can have a look at the screenshots below or alternatively download the sample application.
As you can easily notice, in order to reproduce such an effect, the
ActionBar must overlap the content of the screen. This can be easily done using the
android:windowActionBarOverlay XML attributes. The code below describes the definition of the themes we’ll use:
1 2 3 4 5 6 7 8 9 10 11 12 13
Pretty logically, the style of the
ActionBar is defined in
values/styles.xml as follows:
1 2 3 4 5 6 7 8 9 10
Finally, we can use these themes in order to style our
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Note that by using themes/styles we remove all potential flickering issues at startup (see Android App Launching Made Gorgeous for more information).
Getting the content ready
As explained previously, the
ActionBar fading is synchronized on the per-pixel state scrolling of the scrolling container. In this example, we’ll simply use a
ScrollView as a scrolling container. One of the major drawback of this container is you can’t register a listener in order to be notified when the scroll has changed. This can be easily done be creating a
NotifyingScrollView extending the original
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
Then, we can use this new scrolling container in an XML layout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Fading in/out the ActionBar
Now most of the boilerplate is ready, we can plug all of these components together. The
ActionBar algorithm is rather simple and only consists on computing the alpha depending on the current per-pixel scrolling state of the
NotifyingScrollView. Note that the effective scrolled distance must be clamped to [0, image_height - actionbar_height] in order to avoid weird values that may occur mainly because of the default over scroll behavior of scrolling containers on Android:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
As described in “ActionBar on the Move”, this snippet of code above doesn’t work for pre-JELLY_BEAN_MR1 devices. Indeed, the
ActionBar isn’t invalidating itself when required because it isn’t registering itself as the
Drawable’s callback. You can workaround this issue simply be attaching the following
Callback in the
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3
You can already run the code “as it”. Although the result looks alike the animation used in Play Music we can still continue to tweak it to make it better.
A final brush stroke
Enforcing ActionBar contrast
Having an transparent
ActionBar may lead to design issues because you generally don’t know about the background you’ll be displayed on top of. For instance you may end up with a transparent
ActionBar displaying a white text on top of a white description image. No need to say it makes the
ActionBar invisible and useless.
The easiest way to avoid such a problem consists on modifying the image to make it a little bit darker at the top. Thus, in a worse case scenario (i.e. white image) we would have a grey area on top of the image making the
ActionBar content (title, icons, buttons, etc.) visible.
A simple way to do that is to overlay a translucent dark to transparent gradient on top of the image. This can be done in XML only with the
Drawable described below:
1 2 3 4 5 6 7 8 9 10 11 12
The gradient is overlaid using a wrapping
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
In Gingerbread (API 9), Android introduced a brand new way to notify the user a scrollable container is being scrolled beyond the content bounds. First it introduced the notion of
EdgeEffect (available in the API starting API 14) and enabled over-scroll. While this is not a problem in general, it can be pretty annoying when one of the edge of your scrollable content is different from the background color.
You can reproduce it be simply flinging the
ScrollView rapidly to the top and you’ll notice some white color (the background color) appears on top of the screen because the image is scrolling beyond the bounds. I personally consider this a a UI glitch and usually prefer disabling it in this rare cases.
One could imagine the best way to avoid over-scroll is to use
View#setOverScrollMode(int) to change the mode to
View#OVER_SCROLL_NEVER. Although it works, it also remove the edge effect which can be visually disturbing1. A simple way to do that is to modify the
NotifyingScrollView to force the maximum over scroll values to zero when necessary:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
I seriously don’t know if the team behind the Play Music application decided to implement the behavior based on my article. But it appears they brilliantly used the technique to both polish and emphasize the UI. It is clearly an awesome pattern to use whenever you need to design a screen which content is self-explanatory and is more important than the
ActionBar content itself.
- Do not ask me why the naming of the constants/method is so ambiguous…