在工具栏上方显示ActionMode

96

我正在尝试在使用传统的android.app.ActionBar之外,使用新的android.support.v7.widget.Toolbarandroid.view.ActionMode一起工作。我已经成功地显示了它:

toolbar.startActionMode(callback);
问题在于 ActionMode 被显示在 ActionBar 上而不是 Toolbar 上。有没有办法改变这个呢?我尝试在我的主题中设置以下内容,但似乎没有改变任何东西:
<item name="windowActionModeOverlay">true</item>

1
我认为ActionMode是ActionBar的一部分,您无法更改其位置。 - SpyZip
太糟糕了。感谢您的回答。 - Gaëtan
1
你把工具栏设置为操作栏了吗? - Nikola Despotoski
1
仍然存在同样的问题,有任何更新吗?我遇到了相同的情况,一个工具栏作为经典操作栏,另一个工具栏位于下方,作为内容下方显示的标题和选项菜单。面临这个问题,无法将操作模式向下移动。 - cV2
11个回答

89

首先请确认你导入了正确的命名空间:

既然你正在使用 Toolbar,我还假定你正在使用 AppCompatActivity 并且已经用 setSupportActionBar(toolbar); 方法替换了内置的 ActionBar 为你自己的 Toolbar

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

而不是

import android.view.ActionMode;

然后使用

_actionMode = startSupportActionMode(this);

而不是

_actionMode = startActionMode(this);

40
这个设置加上 windowActionModeOverlay 对我起了作用。 - Jimeux
4
我目前正在使用 AppCompatActivity,并添加 windowActionModeOverlay 就足够了。我尝试使用导入 android.support.v7.view.ActionMode,但它无法与 MultiChoiceModeListener 一起使用,所以我最终使用了 android.view.ActionMode。你知道是否有支持版本的 MultiChoiceModeListener 吗?谢谢。 - Axel
有MultiChoiceModeListener的支持版本吗? - galaxigirl
@galaxigirl,似乎没有。您必须在适配器和视图持有者中处理单击事件。 - Peter Chaula

72

不要在你的活动中启动它,而是在你的工具栏上启动。在你的活动中:

不要在您的Activity中启动它,而是在工具栏上启动。在您的Activity中:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.startActionMode(mActionModeCallback)

你必须使用

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

根据安德烈所述,在您的主题中。


1
这对我有用,因为我也有一个特殊要求。我想要实现MultiChoiceModeListener而不是ActionMode.Callback。使用支持的ActionMode的问题在于似乎没有支持版本的MultiChoiceModeListener - jwir3

46

在您的主题中尝试此方法:

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

正如我在问题中所述,我已经尝试过这个方法但没有成功。不过还是谢谢! - Gaëtan
抱歉,我没有意识到你已经尝试过了。你确定它不起作用吗?对我来说它是有效的。 - André Restivo
我也遇到了同样的问题,这个解决方法很有效。谢谢! - Marta Rodriguez
2
我尝试过使用和不使用android:前缀,并将其放在我的应用程序主题中。 ActionMode覆盖了ActionBar,但我希望它覆盖我的Toolbar,而Toolbar位于ActionBar下方。 - Gaëtan
@Gaëtan,你有没有得到这个问题的答案?我也遇到了同样的问题,但是我正在扩展Activity而不是AppCompatActivity,因为我的应用程序支持API 21及以上。 - Siju

16

我认为人们没有明确的表达出来的一件事是这个线路

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

布局文件放置在Base主题即AppTheme中,而不是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" />


7

经过几天的阅读和试验,我终于让它工作了。以下是我的总结:

注:这是使用 Toolbar 替换 AppCompatActivity 中默认 ActionBar 的解决方案。

  1. 我将以下代码添加到 AppTheme 中:这告诉安卓您希望您的操作模式覆盖工具栏。
<item name="windowActionModeOverlay">true</item>
  1. 使用正确的导入:

为了与AppCompatActivity一起工作,您必须使用以下导入:

import androidx.appcompat.view.ActionMode;
// or
import android.support.v7.view.ActionMode;
  1. 像下面这样在Activity中启动ActionMode:
actionMode = startSupportActionMode(callback);

而不是像这样:

actionMode = startActionMode(callback);

因为设置了supportActionToolbar,所以您的Activity会自动在工具栏上创建ActionMode。样式处理显示为覆盖。

感谢@Kuffs和@Lefty。


7
找到你的AndroidManifest.xml文件,然后在你的应用程序或Activity主题中添加以下代码。
<item name="windowActionModeOverlay">true</item>

所以,就像这样:
<style name="WorkTimeListTheme" parent="AppTheme.NoActionBar">
        <item name="windowActionModeOverlay">true</item>
        <item name="actionModeBackground">@color/theme_primary</item>
    </style>

2
这是我制作的解决方案。
在我的ActionMode.CallbackonCreateActionMode方法中,我添加了以下内容:
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();
  }

对我而言它有效。


2
你可以放弃那些只在特定场景/手机/偶然情况下才有效的垃圾代码,而采用一种非常干净的方式来进行编程:

  1. 创建两个菜单组group:
<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(或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
    }
}

每次都按预期工作。根据需要添加额外的功能。


我支持这个解决方案或类似直接操作工具栏(在我的情况下是MaterialToolbar)的方案。尝试了此帖子中的不同答案,但仅部分成功,因为我无法实现所需的结果(当应用程序主题颜色更改时更改上下文操作栏中图标的色调)。通过修改MaterialToolbar属性,您可以获得与ActionMode相同甚至更多的结果。 - MatJB

1

我尝试了以上所有方法,但仍然无效。然后,我尝试了以下方法:

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

在这里,我使用了支持库的 action mode 和 startSupportActionMode 方法。同时,我也尝试修改给定活动的主题。但是,显然它不起作用。所以,如果你确实没有更好的选择,你可以尝试这个方法。
最近,我发现我使用了 Colorful 框架来启用我的应用程序的多个主题,这将在代码中更改主题。当我尝试修改此框架中的样式时,它有效。
希望它能起作用。

这是唯一对我有效的方法。非常感谢。 - Rachit

0

请确保添加此行:

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

在您的应用程序中使用的主题风格(它写在清单文件中)。

经过数小时的调试,我意识到我正在对一个我甚至没有使用的样式进行更改!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接