You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android ListView条目长按如何在应用顶部覆盖Toolbar显示上下文菜单

要实现长按ListView条目后顶部显示覆盖Toolbar的操作菜单,用Android官方提供的ActionMode上下文操作栏方案即可,具体实现步骤如下:


1. 配置主题支持覆盖Toolbar

在你的app主题(res/values/styles.xml)中添加如下配置,保证ActionMode会覆盖在Toolbar上方,不会把Toolbar挤到下方:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- 其他主题配置 -->
    <item name="windowActionModeOverlay">true</item>
    <item name="actionModeStyle">@style/MyActionModeStyle</item>
</style>

<!-- 可选:自定义ActionMode样式 -->
<style name="MyActionModeStyle" parent="Widget.MaterialComponents.ActionMode.Primary">
    <item name="android:background">?attr/colorPrimary</item>
</style>

2. 新建菜单资源文件

在res/menu目录下新建file_item_menu.xml,定义你需要的操作选项:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/action_delete"
        android:title="删除"
        android:icon="@drawable/ic_delete"/>
    <item
        android:id="@+id/action_share"
        android:title="分享"
        android:icon="@drawable/ic_share"/>
    <item
        android:id="@+id/action_rename"
        android:title="重命名"
        android:icon="@drawable/ic_edit"/>
</menu>

3. 修改FileActivity代码

完整修改后的代码如下:

public class FileActivity extends ListActivity {
    ArrayList<String> al;
    ArrayAdapter<String> adapter;
    ListView lv;
    private ActionMode mActionMode;
    private int mSelectedPosition = -1;

    // ActionMode回调
    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // 加载上下文菜单
            mode.getMenuInflater().inflate(R.menu.file_item_menu, menu);
            mode.setTitle("选择操作");
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            // 处理菜单点击事件
            switch (item.getItemId()) {
                case R.id.action_delete:
                    // 处理删除逻辑
                    String selectedFile = adapter.getItem(mSelectedPosition);
                    // TODO 执行删除操作
                    adapter.remove(selectedFile);
                    mode.finish();
                    return true;
                case R.id.action_share:
                    // 处理分享逻辑
                    mode.finish();
                    return true;
                case R.id.action_rename:
                    // 处理重命名逻辑
                    mode.finish();
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mActionMode = null;
            mSelectedPosition = -1;
            // 可选:取消条目的选中状态
            lv.clearChoices();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.file_view);

        // 安卓6.0以上需要动态申请存储权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
                return;
            }
        }

        ArrayList<String> arr1 = GetFiles(Environment.getExternalStorageDirectory().getPath());
        adapter = new ArrayAdapter<>(getApplicationContext(),
                android.R.layout.simple_expandable_list_item_1, arr1);

        lv = getListView();
        lv.setAdapter(adapter);
        lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

        // 给ListView设置长按监听器
        lv.setOnItemLongClickListener((parent, view, position, id) -> {
            if (mActionMode != null) {
                return false;
            }
            mSelectedPosition = position;
            // 启动ActionMode
            mActionMode = startActionMode(mActionModeCallback);
            view.setSelected(true);
            return true;
        });
    }

    private ArrayList<String> GetFiles(String path) {
        ArrayList<String> arr2 = new ArrayList<>();
        File file = new File(path);
        File[] allfiles = file.listFiles();
        if (allfiles == null || allfiles.length == 0) {
            return arr2;
        }
        for (File f : allfiles) {
            arr2.add(f.getName());
        }
        return arr2;
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        // 如果ActionMode已启动,点击条目切换选中
        if (mActionMode != null) {
            mSelectedPosition = position;
            v.setSelected(true);
            return;
        }
        // 原有点击逻辑处理
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限申请通过,重新加载文件列表
                ArrayList<String> arr1 = GetFiles(Environment.getExternalStorageDirectory().getPath());
                adapter.clear();
                adapter.addAll(arr1);
            }
        }
    }
}

注意事项

  • 你需要自行添加菜单对应的图标资源,或者去掉icon属性只显示文字
  • 如果需要支持多选条目,只需要把ListView的choiceMode改成CHOICE_MODE_MULTIPLE,然后在ActionMode回调中记录所有选中的位置即可
  • 处理文件操作时注意添加对应的存储读写权限,安卓10以上还要适配分区存储规则

内容的提问来源于stack exchange,提问作者S. Najeeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 15:54:07