5
votes

I have been looking a way to change the color of all elements in a toolbar working like an ActionBar dynamically.

Specifications:

  • Using parent="Theme.AppCompat.Light.NoActionBar" on styles.xml
  • Appcompat v7 22
  • setting setSupportActionBar() in my AppCompatActivity
  • I got the colors from a POST request (usually #FF------ format)

I have read following post:

  1. How do I change the color of the ActionBar hamburger icon?
  2. How to change color of hamburger icon in material design navigation drawer
  3. Can't change navigation drawer icon color in android
  4. ActionBarDrawerToggle v7 arrow color
  5. Android Toolbar color change
  6. Android burger/arrow icon dynamic change color (this one worked in someway but I don't like using own image wihtout animation).
    And others links related to this topic... none of them worked for me.

What I'm doing right now is searching for ImageButton on the toolbar (Get reference to drawer toggle in support actionbar), and applying setColorFilter() to all of them like the following code:

for (int i = 0; i < toolbar.getChildCount(); i++){
    if (toolbar.getChildAt(i) instanceof ImageButton) {
        ImageButton ib = (ImageButton) toolbar.getChildAt(i);
        ib.setColorFilter(Color.parseColor("#A74231"), PorterDuff.Mode.SRC_ATOP);
    }
}

I'm changing background and text color with: toolbar.setBackgroundColor and toolbar.setTitleTextColor.

For menu icons (including overflow menu icon):

MenuItem item2 = mMenu.findItem(R.id.actionbar_group_moreoverflow);
item2.getIcon().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);


the QUESTION: is there a better way to do it (change toolbar's elements color dynamically)?

2

2 Answers

6
votes

I was facing same problem here. What I did for ToolBar's elements:

  1. For background color: toolbar.setBackgroundColor(Color.parseColor("#xxxxxxxx"));
  2. For text color: toolbar.setTitleTextColor(Color.parseColor("#xxxxxxxx"));
  3. For hamburger/drawer button:

    int color = Color.parseColor("#xxxxxxxx");
    final PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
    
    for (int i = 0; i < toolbar.getChildCount(); i++){
    
        final View v = toolbar.getChildAt(i);
    
        if(v instanceof ImageButton) {
            ((ImageButton)v).setColorFilter(colorFilter);
        }
    }
    
  4. For ActionMenuItemView (toolbar's buttons including overflow button):

    private void colorizeToolBarItem(AppCompatActivity activity, final PorterDuffColorFilter colorFilter, final String description) {
    
        final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
    
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
    
                final ArrayList<View> outViews = new ArrayList<>();
                decorView.findViewsWithText(outViews, description,
                    View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
                if (outViews.isEmpty())
                    return;
    
                ActionMenuItemView overflow = (ActionMenuItemView)outViews.get(0);
                overflow.getCompoundDrawables()[0].setColorFilter(colorFilter);
                removeOnGlobalLayoutListener(decorView,this);
            }
        });
    }
    
  5. For overflow menu's items text: take a look at this link

1
votes

To get all Toolbar views, iterate through all it’s child views and colorize them separately. The loop code for it looks like this:

public static void colorizeToolbar(Toolbar toolbarView, int toolbarIconsColor, Activity activity) {
    final PorterDuffColorFilter colorFilter
            = new PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.MULTIPLY);

    for(int i = 0; i < toolbarView.getChildCount(); i++) {
        final View v = toolbarView.getChildAt(i);

        //Step 1 : Changing the color of back button (or open drawer button).
        if(v instanceof ImageButton) {
            //Action Bar back button
            ((ImageButton)v).getDrawable().setColorFilter(colorFilter);
        }

        if(v instanceof ActionMenuView) {
            for(int j = 0; j < ((ActionMenuView)v).getChildCount(); j++) {

                //Step 2: Changing the color of any ActionMenuViews - icons that
                //are not back button, nor text, nor overflow menu icon.
                final View innerView = ((ActionMenuView)v).getChildAt(j);

                if(innerView instanceof ActionMenuItemView) {
                    int drawablesCount = ((ActionMenuItemView)innerView).getCompoundDrawables().length;
                    for(int k = 0; k < drawablesCount; k++) {
                        if(((ActionMenuItemView)innerView).getCompoundDrawables()[k] != null) {
                            final int finalK = k;

                            //Important to set the color filter in seperate thread, 
                            //by adding it to the message queue
                            //Won't work otherwise.
                            innerView.post(new Runnable() {
                                @Override
                                public void run() {
                                    ((ActionMenuItemView) innerView).getCompoundDrawables()[finalK].setColorFilter(colorFilter);
                                }
                            });
                        }
                    }
                }
            }
        }

        //Step 3: Changing the color of title and subtitle.
        toolbarView.setTitleTextColor(toolbarIconsColor);
        toolbarView.setSubtitleTextColor(toolbarIconsColor);

        //Step 4: Changing the color of the Overflow Menu icon.
        setOverflowButtonColor(activity, colorFilter);
    }
}

Second,implement the method responsible for finding and colorizing the Overflow Icon:

private static void setOverflowButtonColor(final Activity activity, final PorterDuffColorFilter colorFilter) {
    final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
    final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
    final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
    viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            final ArrayList<View> outViews = new ArrayList<View>();
            decorView.findViewsWithText(outViews, overflowDescription,
                    View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
            if (outViews.isEmpty()) {
                return;
            }
            TintImageView overflow=(TintImageView) outViews.get(0);
            overflow.setColorFilter(colorFilter);
            removeOnGlobalLayoutListener(decorView,this);
        }
    });
}

Toolbar background color

mToolbarView.setBackgroundColor(color);
ToolbarColorizeHelper.colorizeToolbar(mToolbarView, mToolbarIconsColor, getActivity());

Have a look at this link, it may help you https://snow.dog/blog/how-to-dynamicaly-change-android-toolbar-icons-color/