Display ActionMode over Toolbar
Asked Answered
Q

10

96

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>
Quenelle answered 21/10, 2014 at 9:51 Comment(4)
I think ActionMode is part of the ActionBar and you can not change its positionScalariform
That's too bad. Thanks for the answerSwingletree
Have you set the toolbar as actionbar?Copse
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.Calvert
M
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);
Marcille answered 4/5, 2015 at 14:4 Comment(4)
This plus the windowActionModeOverlay setting worked for me.Stevenstevena
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? ThanksStandup
Is there a support version of MultiChoiceModeListener?Probably
@galaxigirl, doesn't seem like there is. You have to handle the click events in your adapter and view holderrBini
C
73

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.

Concede answered 8/12, 2014 at 9:13 Comment(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.Plaintive
C
47

Try this in your theme:

<item name="windowActionModeOverlay">true</item>
Cassimere answered 26/10, 2014 at 19:21 Comment(4)
As stated in my question, I already tryed this without success. But thank you!Swingletree
Sorry, I didn't realise you'd already tried that. Are you sure it doesn't work? It works for me.Eleanor
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.Swingletree
@Quenelle 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.Hydrotherapy
M
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" />

Mollie answered 24/2, 2019 at 15:31 Comment(0)
J
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>
Jerrelljerri answered 21/12, 2018 at 6:51 Comment(0)
S
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.

Schizophrenia answered 23/9, 2020 at 21:53 Comment(0)
N
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.

Ninnetta answered 5/6, 2015 at 9:14 Comment(0)
M
2

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.

Molasses answered 14/1, 2021 at 15:7 Comment(1)
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.Keewatin
D
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.

Dearborn answered 3/1, 2018 at 11:46 Comment(1)
This is the only thing that worked for me. Thanks a lot.Michealmicheil
E
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));
        }
    }
}
Embroider answered 2/3, 2020 at 0:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.