95

I am trying to use the android.view.ActionMode with the new android.support.v7.widget.Toolbar, in addition to the traditional android.app.ActionBar. I am able to display it with:

toolbar.startActionMode(callback);

The problem is that the ActionMode is displayed over the ActionBar, and not over the Toolbar. Is there a way to change that?

I tryied to set the following in my theme, but it does not seem to change anything:

<item name="windowActionModeOverlay">true</item>
Gaëtan
  • 11,912
  • 7
  • 35
  • 45
  • 1
    I think ActionMode is part of the ActionBar and you can not change its position – SpyZip Oct 21 '14 at 11:36
  • That's too bad. Thanks for the answer – Gaëtan Oct 22 '14 at 08:27
  • 1
    Have you set the toolbar as actionbar? – Nikola Despotoski Nov 17 '14 at 13:43
  • 1
    still have the same problem, any updates on this? i got the same situation, one toolbar as classic actionbar, and one toolbar below, as header and optionsmenu for contents shown below. facing this problem, and not able to move the actionmode down. – cV2 Mar 24 '15 at 13:29

11 Answers11

89

Since you are using the Toolbar, I also assume you are using the AppCompatActivity and have replaced the built in ActionBar with your custom Toolbar using setSupportActionBar(toolbar);

First of all ensure you are importing the correct namespace:

import androidx.appcompat.view.ActionMode;
// Or
import android.support.v7.view.ActionMode;

and NOT

import android.view.ActionMode;

then use

_actionMode = startSupportActionMode(this);

and NOT

_actionMode = startActionMode(this);
Anonsage
  • 8,030
  • 5
  • 48
  • 51
Kuffs
  • 35,581
  • 10
  • 79
  • 92
  • 40
    This plus the `windowActionModeOverlay` setting worked for me. – Jimeux Jun 05 '15 at 05:14
  • 4
    I'm currently using `AppCompatActivity` and adding `windowActionModeOverlay` was enough for me. I tried to use import `android.support.v7.view.ActionMode` but it didn't work with `MultiChoiceModeListener`, so I ended up using `android.view.ActionMode` instead. Do you know if there's a support version of `MultiChoiceModeListener`? Thanks – Axel Mar 29 '16 at 04:48
  • Is there a support version of MultiChoiceModeListener? – galaxigirl Apr 05 '17 at 07:27
  • @galaxigirl, doesn't seem like there is. You have to handle the click events in your adapter and view holderr – Peter Chaula Aug 15 '19 at 06:20
72

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>

in your theme as stated by Andre.

Frank
  • 12,010
  • 8
  • 61
  • 78
  • 1
    This worked for me, because I also had a special requirement. Instead of implementing `ActionMode.Callback`, I wanted to implement `MultiChoiceModeListener`. The problem with using the support `ActionMode` is that there doesn't appear to be a support version of the `MultiChoiceModeListener`. – jwir3 May 11 '15 at 17:56
46

Try this in your theme:

<item name="windowActionModeOverlay">true</item>
André Restivo
  • 1,271
  • 14
  • 13
  • As stated in my question, I already tryed this without success. But thank you! – Gaëtan Oct 27 '14 at 06:23
  • Sorry, I didn't realise you'd already tried that. Are you sure it doesn't work? It works for me. – André Restivo Oct 27 '14 at 11:02
  • 2
    I tryied with and without the `android:` prefix, and put it in my application theme. The `ActionMode` overlays the `ActionBar`, but I want it over my `Toolbar`, which is below the `ActionBar`. – Gaëtan Oct 31 '14 at 10:09
  • @Gaëtan Did you get an answer for this? I am having the same issue and I am extending Activity and not AppCompatActivity since my app supports API 21 and above. – Siju Sep 10 '15 at 11:35
16

I think the one thing people are not making clear is that the line

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

is placed in the Base theme i.e AppTheme and not the AppTheme.NoActionBar

<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="windowActionModeOverlay">true</item>
</style>

<style name="transparent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowIsTranslucent">true</item>
</style>


<style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

Lefty
  • 1,192
  • 13
  • 18
7

find your AndroidManifest.xml ,next add below code in your application or Activity theme

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

so like:

<style name="WorkTimeListTheme" parent="AppTheme.NoActionBar">
        <item name="windowActionModeOverlay">true</item>
        <item name="actionModeBackground">@color/theme_primary</item>
    </style>
zhangjin
  • 167
  • 2
  • 5
7

So, after days going thru this thread, I finally got it working. I'd like to summarize what I did.

Note: This is the solution using a Toolbar to replace the default ActionBar in AppCompatActivity.

  1. I added this line to my AppTheme: It tells android that you want your action mode to overlay the toolbar
<item name="windowActionModeOverlay">true</item>
  1. Use the right imports:

You have to use these imports in order to work with AppCompatActivity:

import androidx.appcompat.view.ActionMode;
// or
import android.support.v7.view.ActionMode;
  1. Start the ActionMode on your Activity like so:
actionMode = startSupportActionMode(callback);

And not like so:

actionMode = startActionMode(callback);

You Activity creates the ActionMode on the toolbar automatically, because it's set as the supportActionToolbar. The style handles the dsiplaying as overlay.

Thanks to @Kuffs and @Lefty.

Leon Latsch
  • 671
  • 1
  • 8
  • 13
2

This is the solution I made.

In my onCreateActionMode method of ActionMode.Callback, I add this:

StandaloneActionMode standaloneActionMode = (StandaloneActionMode) actionMode;
Field mContextView;
try {
     mContextView = StandaloneActionMode.class.getDeclaredField("mContextView");
     mContextView.setAccessible(true);
     View contextView = (View) mContextView.get(standaloneActionMode);
     MarginLayoutParams params = (MarginLayoutParams) contextView.getLayoutParams();
     params.topMargin = mToolbar.getTop();
  } catch (NoSuchFieldException e) {
            e.printStackTrace();
  } catch (IllegalAccessException e) {
            e.printStackTrace();
  } catch (IllegalArgumentException e) {
            e.printStackTrace();
  }

It works for me.

Avery
  • 29
  • 1
1

I have tried all the methods above, but it still doesn`t work. And then, I tried the below method:

    private class ActionModeCallback implements ActionMode.Callback {
    @Override
    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
        actionMode.getMenuInflater().inflate(R.menu.note_find_action, menu);
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
        ((AppCompatActivity) getActivity()).getSupportActionBar().hide();
        return false;
    }

    @Override
    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
        return false;
    }

    @Override
    public void onDestroyActionMode(ActionMode actionMode) {
        ((AppCompatActivity) getActivity()).getSupportActionBar().show();
    }
}

Here, I used action mode and startSupportActionMode method of support library. At the same time I have also tried to modify the theme of given activity. Surely, it doesn`t work. So, if you really have no better choice you may try this one.

Just recently, I have found that I used the Colorful frame to enable multiple theme of my app, this will change the theme in code. When I tried to modify the style in this framework, it works.

Hope it works.

Shawn Wong
  • 554
  • 6
  • 15
1

You can leave all the rubbish that only works in certain scenarios/phones/blue moons and simply hack it (in a very clean way):

  1. Create 2 menu groups:
<menu>
    <group android:id="@+id/group_normal">
        <item id="@+id/action_edit"/>
    </group>
    <group android:id="@+id/group_action_mode"
        android:visible="false">
        <item id="@+id/action_mode_1"/>
        <item id="@+id/action_mode_2"/>
        ..
    </group>
</menu>
  1. In your Fragment (or Activity):
class MyFragment: Fragment() {

    private var actionMode = false

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        toolbar.apply {
            setNavigationOnClickListener {
                if(actionMode) endActionMode(this)
                else findNavController().navigateUp()
            }
            setOnMenuItemClickListener {
                when(it.itemId) {
                    R.id.action_edit -> {
                        // start action mode
                        startActionMode(this)
                    }
                    R.id.action_mode_1 -> {
                        // todo
                    }
                    R.id.action_mode_2 -> {
                        // todo
                        endActionMode(this)
                    }
                    ...
                    else -> return@setOnMenuItemClickListener false
                }
                true
            }
        }
    }

    private fun startActionMode(toolbar: Toolbar) {
        with(toolbar.menu) {
            setGroupVisible(R.id.group_normal, false)
            setGroupVisible(R.id.group_action_mode, true)
        }
        toolbar.title = 0 // todo format number of selected items
        actionMode = true
    }

    private fun endActionMode(toolbar: Toolbar) {
        with(toolbar.menu) {
            setGroupVisible(R.id.group_normal, true)
            setGroupVisible(R.id.group_action_mode, false)
        }
        toolbar.setTitle(R.string.original_title)
        actionMode = false
    }
}

Works every time as intended. Add extra functionality as needed.

Ace
  • 2,108
  • 22
  • 29
  • I back this solution or something similar that directly manipulates the Toolbar (MaterialToolbar in my case). Tried the different answers on this post, but only had partial success, as I couldn’t achieve the result I needed (change the tint of the icon in the contextual action bar when my app theme’s color changed). You can get the same result (and even more) than you would with ActionMode by modifying the MaterialToolbar properties. – MatJB Mar 12 '22 at 21:26
0

If you see the view tree,You will can write below code:

 ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
    traverseView(decorView);
 /**
 * traverse find actionmodebar
 * @param root  view
 */
public void traverseView(View root) {
    if (root==null){
        return;
    }
    if (root instanceof ActionBarContextView){
        root.setVisibility(View.GONE);
        return;
    }
    if ((root instanceof ViewGroup)) { // If view is ViewGroup, apply this method on it's child views
        ViewGroup viewGroup = (ViewGroup) root;
        for (int i = 0; i < viewGroup.getChildCount(); ++i) {
            traverseView(viewGroup.getChildAt(i));
        }
    }
}
0

Make sure to put this line:

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

in the style of the theme that you're using in your app (it's written in your manifest file).

After hours of debugging this problem, I realized that I was making changes to a style that I DIDN'T EVEN USE!