5

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)?

Community
  • 1
  • 1
MiguelHincapieC
  • 5,445
  • 7
  • 41
  • 72

2 Answers2

6

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

Community
  • 1
  • 1
  • I'm doing something similar to you based on @Shishram's answer. But still missing how to colorize background and icons of overflow menu. – MiguelHincapieC Sep 18 '15 at 20:46
1

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/

Shishram
  • 1,514
  • 11
  • 20
  • Ty for the answer, but can you explain me more how it's going to help me with the question? (changing it dynamically). No idea if I was not clear enough or there is something in your answer that I'm not seeing, I mean, I said dynamically and without style. – MiguelHincapieC Sep 14 '15 at 19:31
  • sorry for that i have removed all unwanted code, check link in answer it may help you! – Shishram Sep 15 '15 at 05:49
  • sure, I will add essential parts. – Shishram Sep 15 '15 at 10:01
  • Working with it, I'm having some issues about PorterDuff.Mode and guess I found a light way for overflowbutton, let me finish my code and I will complete your answer and mark it like correct (if everything works). – MiguelHincapieC Sep 15 '15 at 20:02
  • Ok after dealing with the code, I'm giving you a resume: I changed PorterDebuff.Mode.MULTIPLY for SRC_ATOP [look at this post and the link in it](http://stackoverflow.com/questions/8280027/what-does-porterduff-mode-mean-in-android-graphics-what-does-it-do). I had to change this line `((ImageButton)v).getDrawable().setColorFilter(colorFilter);` for `((ImageButton)v).setColorFilter(colorFilter);` because first one was not working. Step 2 and 4 are not working, I'm looking what can I do... – MiguelHincapieC Sep 16 '15 at 16:36
  • I'm getting a headache with step 2 `((ActionMenuView)v).getChildCount()` is returning 0 all time! :S @Shishram do you have any idea what is going on? – MiguelHincapieC Sep 16 '15 at 21:14
  • @Shishram I got it, using a method like the one used for overflowmenu, step 2 is working... Now I'm dealing with overflowmenuitems (icon, text and background), those are the last, but Im afraid about those one because I can't find any useful for it here (on SO), [only this](http://stackoverflow.com/a/31252838/1332549)... it has been more than 11 hours working, u_u I'm going to take a rest. – MiguelHincapieC Sep 16 '15 at 23:39