Animating StatusBar color with Collapsing Toolbar

I’ve been charging away at a project and ran across a situation where I couldn’t find a clean solution on GitHub or Stackoverflow. A few hours later and I wanted to share to the interwebs a simple but not so clean code snippet. The problem was how do you fade in a statusbar color over a Activity that used a Translucent statusbar in the theme?

View post on imgur.com

First, here’s my theme. It inherits from ‘Theme.AppCompat.NoActionBar’ with some custom colors.

<style name="DarkTheme.Transparent" parent="DarkTheme">
    <item name="android:windowTranslucentStatus">true</item>
</style>

The meat of the code is all handled inside of an addOnOffsetChangedListener as documented here attached to the AppBar of the layout. It provides me with a method for determining where the AppBar currently is and execute changes. Here’s how to set it up:

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    }
});

The next thing I needed to do was determine when the AppBar was collapsing over the Toolbars normal height. For we can use this:

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    int totalScroll = appBarLayout.getTotalScrollRange();
    int currentScroll = totalScroll + verticalOffset;

    if ((currentScroll) < 255){
         Log.d("HelloWorld", "Overlapping!");
     } else {
         Log.d("HellowWorld", "Not Overlapping!");
     }
});

From here I could’ve simple called getWindow().setStatusBarColor() and called it a day then however I wanted the color to fade in a bit so I found that Color has an argb (int alpha, int red, int green, int blue) method that we can get a color and change its transparency based on how close to fully collapsed we are.

To start we need to get the RGB values of our intended color.

int color = ContextCompat.getColor(context, R.color.colorPrimaryDark);
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = (color >> 0) & 0xFF;

This allows us to pass our RGB values plus an Alpha value to Color.argb(int,int,int,int) to get a color at each stage of the scrolling. A small problem I found was that as currentScroll nears zero we need to get the opposite value for the Alpha to work correctly. Since the Alpha value goes from 0 to 255 I used that as the starting point for animating in the color on the status bar. The only problem is currentScroll counts down from 255 to 0 and I needed Alpha value to count up to 255.

public int reverseNumber(int num, int min, int max) {
    return (max + min) - num;
}

So if the toolbar is at currentScroll – 254 I can set Color.agrb to (1 , R, G, B). Lastly all I had to do was clear window flags and set the color in the logic, full code below:

    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            int totalScroll = appBarLayout.getTotalScrollRange();
            int currentScroll = totalScroll + verticalOffset;

            Timber.v("AppBar totalScroll: %s currentScroll: %s verticalOffset: %s",
                    totalScroll, currentScroll, verticalOffset);
            int color = statusColor;
            int r = (color >> 16) & 0xFF;
            int g = (color >> 8) & 0xFF;
            int b = (color >> 0) & 0xFF;

            if ((currentScroll) < 255){
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    Timber.v("ColorNew: %s ColorPrimary: %s R: %s G: %s B: %s",
                            reverseNumber(currentScroll,0,255), R.color.colorPrimary,r,g,b);
                    Window window = getWindow();
                    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                    window.setStatusBarColor(Color.argb(reverseNumber(currentScroll,0,255),r,g,b));
                }
            } else {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    Window window = getWindow();
                    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                }
            }
        }
    });
}

public int reverseNumber(int num, int min, int max) {
    int number = (max + min) - num;
    Timber.d("Number: %s",number);
    return number;
}

Hope this is helpful to someone, project available on GitHub.

« »

© 2017 The Jones Theory. Theme by Anders Norén.