Display ActionMode over Toolbar

AndroidAndroid Support-LibraryAndroid ToolbarAndroid Actionmode

Android Problem Overview


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>

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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.

Solution 3 - Android

Try this in your theme:

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

Solution 4 - Android

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" />

Solution 5 - Android

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>

Solution 6 - Android

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.

Solution 7 - Android

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.

Solution 8 - Android

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.

Solution 9 - Android

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.

Solution 10 - Android

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));
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGa&#235;tanView Question on Stackoverflow
Solution 1 - AndroidKuffsView Answer on Stackoverflow
Solution 2 - AndroidFrankView Answer on Stackoverflow
Solution 3 - AndroidAndré RestivoView Answer on Stackoverflow
Solution 4 - AndroidLeftyView Answer on Stackoverflow
Solution 5 - AndroidzhangjinView Answer on Stackoverflow
Solution 6 - AndroidLeon LatschView Answer on Stackoverflow
Solution 7 - AndroidAveryView Answer on Stackoverflow
Solution 8 - AndroidJeff WongView Answer on Stackoverflow
Solution 9 - AndroidAceView Answer on Stackoverflow
Solution 10 - Androiduser2416658View Answer on Stackoverflow