183

I am working on using the newly added Toolbar that was introduced in Lollipop and the AppCompat-v7 library. I followed this guide on setting up the Toolbar I noticed that when you invoke something that will bring up the contextual ActionBar (such as highlighting text for copy/pasting), that it will push the Toolbar down on the page. You can see what I am talking about in the image at the bottom of the page:

So, essentially, I set it up like this. I have the Toolbar defined in an xml file that I use with include tags:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"/>

Then, I instantiate it in my view:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/root"
    tools:context=".MainActivity">

    <include
        layout="@layout/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/> 

    <!-- Rest of view -->

    </LinearLayout>

In code, I set it up like so:

    // On Create method of activity:
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

Does anyone know how to make it so that the Contextual ActionBar comes overtop of the Toolbar?

Toolbar and Contextual ActionBar

MrEngineer13
  • 37,296
  • 12
  • 71
  • 92
ariets
  • 4,098
  • 4
  • 25
  • 34

7 Answers7

324

Update:

Solution: use the windowActionModeOverlay property. Set this in your theme:

<item name="windowActionModeOverlay">true</item>

and the actionmode will be shown over the action bar instead of pushing it down. (If you're not using the latest AppCompat then you need to add the "android:" prefix to the property). It basically lets AppCompat know that you have a toolbar located in the top of the screen and that it should draw the ActionMode on top of it.


Old answer/workaround:

I ran into the same problem. No matter what theme I set, it always pushes down the Toolbar I set as ActionBar. I tried with and without the support library, but it didn't matter.

Unfortunately I was not able to fix it so I have built a workaround instead. In my ActionModeCallback's onCreateActionMode I hide the action bar:

actionBarToolbar.setVisibility(View.GONE);

and in onDestroyActionModeI show it again:

actionBarToolbar.setVisibility(View.VISIBLE);

The hiding/showing happens so quickly it is not noticeable on my test devices. There is of course a downside: although the enter-animation still works, the exit-animation of the contextual action bar gets lost because the Toolbar immediately pops over it. But until we come across a better solution I guess we are stuck with this.


(My Activity is actually extending a custom BaseActivity class which has a method called getActionBarToolbar(), taken from the Google I/O 2014 app source code, so I can easily get fetch the Toolbar:

BaseActivity activity = (BaseActivity) getActivity();
activity.getActionBarToolbar().setVisibility(View.GONE);

Too bad the I/O app does not use the contextual action bar.)

Community
  • 1
  • 1
Jacob Ras
  • 5,743
  • 1
  • 23
  • 24
  • Yeah, this was the only solution I could come to as well. However, there are cases where teh Contextual ActionBar happens from the system (for example in a WebView or with an EditText). Those you do not get the callbacks for. So, how would you go about showing/hiding it for that? (Or am I wrong and you can, in fact, get the callbacks for the CAB with those)? – ariets Oct 19 '14 at 15:36
  • 1
    Yes, you can [TextView.setCustomSelectionActionModeCallback()](http://developer.android.com/reference/android/widget/TextView.html#setCustomSelectionActionModeCallback(android.view.ActionMode.Callback)) for that, like Aleksandar described in his answer. – Jacob Ras Oct 20 '14 at 10:21
  • 1
    Oh, already cannot update my comment anymore. Small addition: it seems like setCustomSelectionActionModeCallback cannot be used with the ActionModeCallback from the support library. I am using a VERSION.SDK_INT check to set it. Still need to test if the problem also occurs on pre-Honeycomb devices. – Jacob Ras Oct 20 '14 at 10:32
  • @ariets please see my updated answer. I feel a bit dump for having completely forgotten that property, but at least we can get rid of the workaround now ;-) – Jacob Ras Oct 20 '14 at 12:23
  • 1
    Funny I'm using the latest (compile 'com.android.support:appcompat-v7:22.0.0') but I have to leave out the android: part for it to work... – Warpzit Mar 18 '15 at 14:32
  • @JacobRas what is the difference between adding the "android:" prefix or not? I mean, how do you when to use one or the other? Thanks. – Axel Mar 29 '16 at 04:57
  • @Axel if you're using / styling system (from the android OS framework) components include the android: If it's from the support lib, drop the android prefix (although some trial and error still seems to be necessary unfortunately) – cargo8 Sep 27 '16 at 18:49
  • how can i change that background color – Harsha Oct 18 '16 at 07:24
  • I didn't notice that I had the "android:" prefix before "windowsActionModeOverlay". Once I removed it, it worked. – Miki P May 31 '17 at 18:30
16

Do not start it on your activity, but on your toolbar. In you activity:

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.startActionMode(mActionModeCallback)

and you have to use

<item name="windowActionModeOverlay">true</item>
Frank
  • 11,222
  • 7
  • 58
  • 76
  • for me it does for android.support.v7.app.ActionBar – Frank Feb 23 '15 at 10:54
  • I get this error-> startActionMode (android.view.ActionMode.Callback) in View cannot be applied to (android.support.v7.view.ActionMode.Callback) – Faheem Feb 23 '15 at 11:04
  • Ah, okay. My min version is not smaller than 11. So I can use a android.view.ActionMode. Callback on a android.support.v7.widget.Toolbar, I never used android.support.v7.view.ActionMode.Callback. – Frank Feb 23 '15 at 12:38
  • It's worth mentioning `AppCompatActivity.startSupportActionMode(callback)`, to get compatibility with attributes like `app:iconTint` in menu item xmls. – geekley Feb 06 '20 at 00:25
14

Just a small addition: For

<item name="windowActionModeOverlay">true</item>
to work it's important to call super.onCreate(savedInstanceState) BEFORE calling setContentView(R.layout.your_activity) in your activity. It really makes a difference in this case!
Daniel Veihelmann
  • 1,162
  • 9
  • 13
11

In my case, <item name="windowActionModeOverlay">true</item>did not work, but this work:<item name="android:windowActionModeOverlay">true</item>,the android is the key.

Jenkyn
  • 140
  • 2
  • 9
8

Jacob's solution worked for me but the contextual ActionBar was transparent and the Toolbar visible through it. This can be resolved as follows:

<style name="AppTheme.Base" parent="Theme.AppCompat.Light">
    ....
    ....
    <item name="actionModeStyle">@style/CustomActionMode</item>
</style>

<style name="CustomActionMode" parent="@style/Widget.AppCompat.ActionMode">
    <item name="background">@color/primary_material_light</item>
</style>

The theme "AppTheme.Base" must be the one applied to the Toolbar.

More details regarding contextual ActionBar styling:

how to Customize the Contextual Action Bar using appCompat in material design

Community
  • 1
  • 1
Pete
  • 189
  • 3
  • 11
0

Very useful method to bring toolbar to front toolbar.bringToFront()

kunal.c
  • 2,669
  • 1
  • 14
  • 24
  • 2
    `View.bringToFront()` is very heavy operation and generally should be avoided at any cost. – dominus Jun 04 '15 at 12:39
  • You right, but for animation for e.g top to bottom of screen will overlap the toolbar. Hence we need to use toolbar.bringToFront() to animate below toolbar.If there is any alternate way you can share : ) – kunal.c Jun 05 '15 at 04:23
0

Another small addition: make sure to set at least an empty screen in the activity via setContentView(R.layout.empty_screen) if you load the whole ui in fragments (ft.replace(android.R.id.content, fragment)).

Andreas Wenger
  • 3,970
  • 19
  • 30