Styling the ActionMode Overflow Menu

May 11, 2016

Styling the ActionMode Overflow Menu

Styling the overflow menu of an ActionMode is a very specific task that is surprisingly sparsely documented. Determining the correct style to apply to a specific widget in an Android app can often be a daunting task that traverses a deep rabbit hole.

If your app is keeping up with the times and you’re using the appcompat-v7 support library, your app’s theme is some variant of Theme.AppCompat, your Activities extend AppCompatActivity, and you may have switched to using Toolbar instead of an Action Bar.

Toolbar as Action Bar

You set the Toolbar in your layout to act as your action bar with

<span class="n">setSupportActionBar</span><span class="o">(</span><span class="n">toolbar</span><span class="o">);</span>

One of the first steps in setting up your app’s theme is selecting a primary color.

<span class="nt"><style< span=""> <span class="na">name=</span><span class="s">"AppTheme"</span> <span class="na">parent=</span><span class="s">"Theme.AppCompat"</span><span class="nt">></span>
 <span class="nt"><item< span=""> <span class="na">name=</span><span class="s">"colorPrimary"</span><span class="nt">></span>@color/primary_app_color<span class="nt"></span>
<span class="nt"></span>
</item<></span></style<></span>

Which will style our Action Bar/Toolbar like this:



Starting an ActionMode

You activate an ActionMode with

<span class="kn">import</span> <span class="nn">android.support.v7.view.ActionMode</span><span class="o">;</span>

<span class="kd">private</span> <span class="n">ActionMode</span> <span class="n">actionMode</span><span class="o">;</span>

<span class="kd">private</span> <span class="kt">void</span> <span class="nf">startMyActionMode</span><span class="o">()</span> <span class="o">{</span>
 <span class="n">actionMode</span> <span class="o">=</span> <span class="n">startSupportActionMode</span><span class="o">(</span><span class="k">new</span> <span class="n">CustomActionCallback</span><span class="o">());</span>
<span class="o">}</span>

<span class="kd">private</span> <span class="kd">class</span> <span class="nc">CustomActionCallback</span> <span class="kd">implements</span> <span class="n">ActionMode</span><span class="o">.</span><span class="na">Callback</span> <span class="o">{</span>
 <span class="nd">@Override</span>
 <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onCreateActionMode</span><span class="o">(</span><span class="n">ActionMode</span> <span class="n">mode</span><span class="o">,</span> <span class="n">Menu</span> <span class="n">menu</span><span class="o">)</span> <span class="o">{</span>
 <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
 <span class="o">}</span>

 <span class="nd">@Override</span>
 <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onPrepareActionMode</span><span class="o">(</span><span class="n">ActionMode</span> <span class="n">mode</span><span class="o">,</span> <span class="n">Menu</span> <span class="n">menu</span><span class="o">)</span> <span class="o">{</span>
 <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
 <span class="o">}</span>

 <span class="nd">@Override</span>
 <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onActionItemClicked</span><span class="o">(</span><span class="n">ActionMode</span> <span class="n">mode</span><span class="o">,</span> <span class="n">MenuItem</span> <span class="n">item</span><span class="o">)</span> <span class="o">{</span>
 <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
 <span class="o">}</span>

 <span class="nd">@Override</span>
 <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onDestroyActionMode</span><span class="o">(</span><span class="n">ActionMode</span> <span class="n">mode</span><span class="o">)</span> <span class="o">{</span>

 <span class="o">}</span>
<span class="o">}</span>

When we start our ActionMode, we get an overlay over our Action Bar/Toolbar like this:

The overflow menu for this ActionMode uses colorPrimary as its default background.

How to style the ActionMode overflow menu

So how do you style the text and background of an ActionMode overflow menu being displayed on top of a Toolbar being used as a support Action Bar? Here’s how.

<span class="nt"><style< span=""> <span class="na">name=</span><span class="s">"AppTheme"</span> <span class="na">parent=</span><span class="s">"Theme.AppCompat"</span><span class="nt">></span>
 <span class="nt"><item< span=""> <span class="na">name=</span><span class="s">"actionBarPopupTheme"</span><span class="nt">></span>@style/ActionModeOverflowMenu<span class="nt"></span>
<span class="nt"></span>

<span class="nt"><style< span=""> <span class="na">name=</span><span class="s">"ActionModeOverflowMenu"</span> <span class="na">parent=</span><span class="s">"Widget.AppCompat.ListPopupWindow"</span><span class="nt">></span>
 <span class="nt"><item< span=""> <span class="na">name=</span><span class="s">"android:textColor"</span><span class="nt">></span>@color/actionmode_overflow_menu_text<span class="nt"></span>
 <span class="nt"><item< span=""> <span class="na">name=</span><span class="s">"android:background"</span><span class="nt">></span>@color/actionmode_overflow_menu_background<span class="nt"></span>
<span class="nt"></span>
</item<></span></item<></span></style<></span></item<></span></style<></span>

After we apply the new ActionModeOverflowMenu to our theme, the overflow menu colors are now customized the way we want them.

The Android style rabbit hole

The difficulty in getting certain styles to correctly apply to your app lies in determining what magical incantation of style attributes and parent styles to extend and if you are using the appcompat-v7 support libraries (which you almost certainly should be doing). You will need to do the following:

  • Set the correct attribute in your theme (actionBarPopupTheme)
  • Have your style extend the correct parent style (Widget.AppCompat.ListPopupWindow)
  • Override the correct attributes in the style (android:textColor, android:background)

In this case, we leave the android: prefix off of actionBarPopupTheme since it is a support-compatibility attribute but we leave it on ActionModeOverflowMenu’s attributes. Often only through trial and error will you discover what attributes need to be prefixed with “android:” and which ones don’t, and in what circumstances.

Style attributes are often not well defined or documented, so it is often helpful to make use of your IDE’s (IntelliJ or Android Studio) ability to follow style declarations (by pressing Ctrl/Command and clicking on them). You will find yourself using this extensively to determine what built-in Android attributes you will need to override and what built-in Android styles you will need to set as your new style’s parent style.

Ready to get started?

Call us at (616) 594-0269 or send us a note below.
Visit our office @ 452 Ada Drive SE Suite 300 Ada, Michigan 49301
Send us an e-mail @ info@michiganlabs.com