Toolbar and Contextual ActionBar with AppCompat-v7
Asked Answered
L

7

184

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

Laureenlaurel answered 18/10, 2014 at 18:57 Comment(2)
What theme is your activity using?Apiarist
David, I just clicked the link and it seems to be working for me.Laureenlaurel
L
325

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

Limon answered 19/10, 2014 at 13:11 Comment(9)
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)?Laureenlaurel
Yes, you can TextView.setCustomSelectionActionModeCallback() for that, like Aleksandar described in his answer.Limon
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.Limon
@Laureenlaurel 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 ;-)Limon
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...Hypopituitarism
@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.Donohoe
@Donohoe 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)Desdemona
how can i change that background colorHomothallic
I didn't notice that I had the "android:" prefix before "windowsActionModeOverlay". Once I removed it, it worked.Derrick
P
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>
Percyperdido answered 8/12, 2014 at 9:15 Comment(4)
for me it does for android.support.v7.app.ActionBarPercyperdido
I get this error-> startActionMode (android.view.ActionMode.Callback) in View cannot be applied to (android.support.v7.view.ActionMode.Callback)Tungusic
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.Percyperdido
It's worth mentioning AppCompatActivity.startSupportActionMode(callback), to get compatibility with attributes like app:iconTint in menu item xmls.Jollification
Y
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!
Yarbrough answered 3/2, 2015 at 16:23 Comment(0)
B
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.

Bactericide answered 25/1, 2015 at 16:20 Comment(3)
You use <item name="windowActionModeOverlay">true</item> with the appcompat toolbar, otherwise you use the android namespace.Unstuck
no use for me in my layout am adding toolbar,in the activity initialize toolbar and setsupport true done please help meHomothallic
<item name="windowActionModeOverlay">true</item> worked as expected!Labellum
S
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

Smithson answered 29/7, 2015 at 6:2 Comment(0)
C
0

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

Crescen answered 16/12, 2014 at 9:25 Comment(2)
View.bringToFront() is very heavy operation and generally should be avoided at any cost.Brinkema
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 : )Crescen
D
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)).

Daffie answered 23/3, 2015 at 18:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.