android – CollapsingToolbarLayout: Change home button color when expanded-ThrowExceptions

Exception or error:

I have implemented the new CollapsingToolbarLayout from Chris Banes example code.

However, the images for the backdrop image view have all a white background. The toolbar theme is ThemeOverlay.AppCompat.Dark.ActionBar so the icons are white too, thus I can’t see the home button when the CollapsingToolbarLayout is fully expanded.

With app:expandedTitleTextAppearance i can set the color for the title field. Is there also a possibility to set the color of the home buttons and menu icons?

How to solve:

Here is the example how I change my drawer and options icons color when layout is expanded and collapsed:

protected void onCreate(Bundle savedInstanceState) {
            AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
            appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
                @Override
                public void onOffsetChanged(AppBarLayout appBarLayout, int offset)
                {
                    Drawable upArrow = ResourcesCompat.getDrawable(getResources(), R.drawable.drawer_icon, null);
                    if (offset < -200)
                    {
                        upArrow.setColorFilter(Color.parseColor("#000000"), PorterDuff.Mode.SRC_ATOP);
                        getSupportActionBar().setHomeAsUpIndicator(upArrow);

                        Drawable drawable = ContextCompat.getDrawable(getApplicationContext(),R.drawable.option_menu_icon);
                        drawable.setColorFilter(Color.parseColor("#000000"), PorterDuff.Mode.SRC_ATOP);
                        toolbar.setOverflowIcon(drawable);
                    }
                    else
                    {

                        upArrow.setColorFilter(Color.parseColor("#ffffff"), PorterDuff.Mode.SRC_ATOP);
                        getSupportActionBar().setHomeAsUpIndicator(upArrow);
                        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

                        Drawable drawable = ContextCompat.getDrawable(getApplicationContext(),R.drawable.option_menu_icon);
                        drawable.setColorFilter(Color.parseColor("#ffffff"), PorterDuff.Mode.SRC_ATOP);
                        toolbar.setOverflowIcon(drawable);
                    }
        }
});

###

It is better to use 2 different images in Toolbar. Others may cause some unwanted problems:

  1. Trying to set 2 different Toolbar themes will never work because themes are set only on Activity creation, setting another theme has no effect, you need to re-create the Activity.
  2. Using color filter may not result what exactly you want. You may use shadowed arrow and color filter will also paint that shadow which becomes more like outer glow.

So your Toolbar will look like this:

<android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:contentInsetStart="0dp"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|enterAlways|snap">

            <ImageView
                android:id="@+id/imageViewBack"
                android:layout_width="?attr/actionBarSize"
                android:layout_height="?attr/actionBarSize"
                android:scaleType="center"
                android:src="@drawable/button_back_white" />

</android.support.v7.widget.Toolbar>

And you will set imageViewBack drawable as your Toolbar collapses:

appBarLayout.addOnOffsetChangedListener((appBarLayout, offset) -> {
        final boolean isCollapsed = (offset == (-1 * appBarLayout.getTotalScrollRange()));

        imageViewBack.setImageDrawable(ContextCompat.getDrawable(context,
        isCollapsed ? 
        R.drawable.button_back_red : 
        R.drawable.button_back_white));
});

###

In my eyes this is only possible if you change the drawables of the home button, the menu icons and the overflow button. Fortunately Google has give us a new API called Tinted Drawables which allows us to set the collor of a drawable or nine-patch image. Here is how it works:

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@android:drawable/ic_menu_camera"
    android:tint="@color/menu_icon_color"/>

Now you can use this new defined Drawable like any other in your layout. For the home button and the overflow button you also have to override the style definitions like so:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:homeAsUpIndicator">@drawable/tinted_home_button</item>
    <item name="android:actionOverflowButtonStyle">@style/OverFlowButton</item>
</style>

<style name="OverFlowButton" parent="AppTheme">
    <item name="android:src">@drawable/tinted_overflow_button</item>
</style>

All these stuff (except the style definitions) is unfortunately only available on API level 21+ and is not included into the support library. If you have to support devices lower then Lollipop I think the best way is to use the Android Assets Studio where you can tint the icons by yourself and download them as a png file.

###

The home button, overflow button, and some select stock icons from the sdk are affected by colorControlNormal:

<style name="ActionBar" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="colorControlNormal">@color/accent</item>
</style>

If you have other icons, you would need to loop through and manually filter them:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.sample_actions, menu);

    for(int i = 0; i < menu.size(); i++){
        Drawable drawable = menu.getItem(i).getIcon();
        if(drawable != null) {
            drawable.mutate();
            drawable.setColorFilter(getResources().getColor(R.color.accent), PorterDuff.Mode.SRC_ATOP);
        }
    }

    return true;
}

###

You can get a nice color transition while scrolling with the following approach using a ColorFilter. Hope you like Kotlin

app_bar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout: AppBarLayout, offset: Int ->
    val colorComponent = Math.max(0.3f,offset.toFloat() / -appBarLayout.totalScrollRange)
    toolbar.navigationIcon?.colorFilter = 
    PorterDuffColorFilter(Color.rgb(colorComponent, colorComponent, colorComponent), PorterDuff.Mode.SRC_ATOP)
})

This will give you a dark navigation icon when the CollapsingToolbarLayout is expanded and a white icon in collapsed state.

Leave a Reply

Your email address will not be published. Required fields are marked *