Search code examples
androidandroid-toolbarandroid-stylesandroid-actionmode

Light action mode on dark toolbar


I'm trying to display a light action mode (white background, black text, black icons) on a dark toolbar (custom-colored background via the primary color, white text, white icons).

Here's the definition of my Toolbar in my activity's layout:

<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/activity_press_toolbar_background"
        android:theme="@style/AppTheme.MainToolbar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

Here's the mentionned AppTheme.MainToolbar:

<style name="AppTheme.MainToolbar" parent="@style/ThemeOverlay.AppCompat.ActionBar"/>

With those style definitions, everything is like I want it, excepted for the overflow icon on the "default" toolbar (non action-mode), which is black instead of white. If I inherit from @style/ThemeOverlay.AppCompat.Dark.ActionBar for the Toolbar theme, the overflow is white, but the action mode is also turned dark: dark-grey background, white text and icons.

I tried to redefine pretty much everything in my action mode style:

<style name="AppTheme.ActionMode" parent="Widget.AppCompat.ActionMode">
    <item name="background">@android:color/white</item>
    <item name="android:titleTextStyle">@style/AppTheme.ActionMode.Title</item>
    <item name="titleTextStyle">@style/AppTheme.ActionMode.Title</item>
    <item name="actionOverflowButtonStyle">@style/AppTheme.ActionMode.Overflow</item>
    <item name="android:actionOverflowButtonStyle">@style/AppTheme.ActionMode.Overflow</item>
</style>

<style name="AppTheme.ActionMode.Title" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
    <item name="android:textColor">@android:color/black</item>
</style>

<style name="AppTheme.ActionMode.Overflow" parent="Widget.AppCompat.ActionButton.Overflow">
    <item name="android:tint">#000000</item>
</style>

I used this ActionMode style in my main style:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- ... -->
    <item name="actionModeStyle">@style/AppTheme.ActionMode</item>
    <item name="android:actionModeStyle">@style/AppTheme.ActionMode</item>
</style>

Everything is working… excepted the overflow color. In action mode, it's white (on white, so…). If I set the actionOverflowButtonStyle attributes on my main style, the overflow is tinted properly - but on the whole application, action mode included.

Redefining the whole style doesn't sound right - and doesn't work anyway, at least for the overflow. But I can't find a way to define a light action mode on a dark action bar. Is there any way to do so?


Solution

  • Here's a method to fix this, but I'm sure there's a better way. If you have a better solution, please, please post it. If you haven't and are stuck with the same problem, feel free to use this, but be aware that it relies on the implementation of the overflow button and content description inherent to support libraries. It works as of v26, it may not work with another version. Check this whenever you update your support libraries.

    private static void setOverflowButtonColor(@ColorRes final int color, @NonNull final Activity activity) {
        final String contentDescription = activity.getResources().getString(R.string.abc_action_menu_overflow_description);
        final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                final ArrayList outViews = new ArrayList(1);
                decorView.findViewsWithText(outViews, contentDescription, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
                if (!outViews.isEmpty()) {
                    if (outViews.get(0) instanceof AppCompatImageView) {
                    ((AppCompatImageView) outViews.get(0)).setColorFilter(ContextCompat.getColor(activity, color));
                    decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                }
            }
        });
    }