Reputation: 12562
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>
Upvotes: 97
Views: 32501
Reputation: 2228
You can leave all the rubbish that only works in certain scenarios/phones/blue moons and simply hack it (in a very clean way):
group
s:<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>
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.
Upvotes: 2
Reputation: 751
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 defaultActionBar
inAppCompatActivity
.
AppTheme
: It tells android that you want your action mode to overlay the toolbar<item name="windowActionModeOverlay">true</item>
You have to use these imports in order to work with AppCompatActivity
:
import androidx.appcompat.view.ActionMode;
// or
import android.support.v7.view.ActionMode;
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.
Upvotes: 7
Reputation: 1
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));
}
}
}
Upvotes: 0
Reputation: 35651
Since you are using the
Toolbar
, I also assume you are using theAppCompatActivity
and have replaced the built inActionBar
with your customToolbar
usingsetSupportActionBar(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);
Upvotes: 90
Reputation: 1422
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" />
Upvotes: 16
Reputation: 167
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>
Upvotes: 7
Reputation: 648
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.
Upvotes: 1
Reputation: 29
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.
Upvotes: 2
Reputation: 12308
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.
Upvotes: 73
Reputation: 1300
Try this in your theme:
<item name="windowActionModeOverlay">true</item>
Upvotes: 48