ContextMenu:上下文菜单

QuibblerQuibbler 2020-05-20 约 15 分钟 1811 次阅读

ContextMenu:上下文菜单

在Activity中长按某个View会弹出一个菜单,类似Windows上右键弹出的菜单。在Activity中只需要实现已有的几个空方法即可自定义上下文菜单:onCreateContextMenu、onContextItemSelected、onContextMenuClosed。不同的手机系统,显示样式和特性稍有差异。

1、ContextMenu

传统Menu的上下文菜单扩展,提供了修改上下文菜单标题的功能。上下文菜单不支持快捷方式和图标。长按时显示上下文菜单,只需要在Activity中调用Activity.registerForContextMenu(),并重写Activity.onCreateContextMenu()方法。

ContextMenu是继承Menu的接口

public interface ContextMenu extends Menu {
    /**
     * 将上下文菜单标题的标题设置为titleRes资源标识符中给定的标题。
     * 
     */
    public ContextMenu setHeaderTitle(@StringRes int titleRes);
    /**
     * 将上下文菜单标题的标题设置为title中给定的标题。
     * 
     */
    public ContextMenu setHeaderTitle(CharSequence title);
    
    /**
     * 将上下文菜单标题的图标设置为iconRes资源ID中给定的图标。
     * 
     */
    public ContextMenu setHeaderIcon(@DrawableRes int iconRes);
    /**
     * 将上下文菜单标题的图标设置为Drawable图标中给定的图标。
     * 
     */
    public ContextMenu setHeaderIcon(Drawable icon);
    
    /**
     * 将上下文菜单的标题设置为view中给定的View。 这将替换标题和图标(然后替换标题和图标)。
     * 
     */
    public ContextMenu setHeaderView(View view);
    
    /**
     * 清除上下文菜单的标题。
     */
    public void clearHeader();
    
    /**
     * 有关创建上下文菜单的其他信息。 例如,AdapterView使用它在启动上下文菜单的适配器中传递确切的项目位置。
     */
    public interface ContextMenuInfo {
    
    }
}

2、实现上下文菜单

重写Activity.onCreateContextMenu()方法创建上下文菜单。

2.1、代码方式

直接调用ContextMenu参数对象add(int groupId, int itemId, int order, CharSequence title)方法,添加菜单项。

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(0, 0, 1, "文件");
        menu.add(0, 1, 2, "打开");
        menu.add(0, 2, 3, "关闭");
        menu.add(1, 3, 4, "剪切");
        menu.add(1, 4, 5, "复制");
        menu.add(1, 5, 6, "移动");
    }

2.2、加载xml菜单

通过MenuInflater加载xml布局。

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.file_context_menu, menu);
    }

定义在res/menu/中的xml菜单:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/file"
        android:icon="@drawable/setting_icon_2"
        android:title="文件"
        app:showAsAction="always" />
    <item
        android:id="@+id/open"
        android:title="打开" />
    <item
        android:id="@+id/close"
        android:title="关闭" />
    <item
        android:id="@+id/cut"
        android:title="剪切" />
    <item
        android:id="@+id/copy"
        android:title="复制" />
    <item
        android:id="@+id/move"
        android:title="移动" />
</menu>

3、注册上下文菜单

给View注册上下文菜单,长按会弹出ContextMenu:registerForContextMenu(View view),注册要在给定View中显示的上下文菜单(多个视图可以显示上下文菜单)。 此方法会将视图上的OnCreateContextMenuListener设置为此活动,因此在显示上下文菜单时将调用onCreateContextMenu(ContextMenu,View,ContextMenuInfo)

@Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        registerForContextMenu(mView);
    }

ContextMenu也需要反注册,提供了反注册方法:unregisterForContextMenu(View view),禁止显示给定视图的上下文菜单。 此方法将删除视图上的OnCreateContextMenuListener。

@Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterForContextMenu(mView);
    }

也可以直接调用View的setOnCreateContextMenuListener(OnCreateContextMenuListener l)方法,给指定View设置上下文监听器,也就是当前Activity。

mView.setOnCreateContextMenuListener(this::onCreateContextMenu);

取消直接设置为null即可:

mView.setOnCreateContextMenuListener(null);

4、上下文菜单点击

上下文菜单选项点击的时候会调用onContextItemSelected(MenuItem item)方法。

前面代码方式手动添加的菜单项,传入的参数有菜单组groupId和菜单id,可以通过下面的方式获取到。

int id = item.getItemId();
    int groudID = item.getGroupId();

使用布局加载ContextMenu的时候不建议,因为这个时候id是布局中随机生成的R.id,直接引用布局中的id判断即可。

@Override
    public boolean onContextItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.file:
                //
                break;
            case R.id.open:
                //
                break;
            case R.id.close:
                //
                break;
            case R.id.cut:
                //
                break;
            case R.id.copy:
                //
                break;
            case R.id.move:
                //
                break;
            default:
                break;
        }
        return true;
    }

5、ContextMenu相关源码

5.1、registerForContextMenu/unregisterForContextMenu

在Activity类中该方法的定义:

public void registerForContextMenu(View view) {
        view.setOnCreateContextMenuListener(this);
    }

调用View的setOnCreateContextMenuListener方法。内部将View设置为可长按,同时设置上下文监听器。

public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
        if (!isLongClickable()) {
            setLongClickable(true);
        }
        getListenerInfo().mOnCreateContextMenuListener = l;
    }

5.2、OnCreateContextMenuListener 

前面设置ContextMenu的OnCreateContextMenuListener,也就是当前Activity。

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        
    }

在父类Activity中是空方法,也就是实现上下文菜单的时候需要重写该方法创建菜单。

OnCreateContextMenuListener接口定义在View中。

public interface OnCreateContextMenuListener {
        / **
          *在构建此视图的上下文菜单时调用。 此方法返回后,保持菜单不安全
          *
          * @param menu 正在构建的上下文菜单
          * @param v 要为其构建上下文菜单的视图
          * @param menuInfo 有关应为其显示上下文菜单的项目的额外信息。 该信息将根据v的类别而变化。
          * /
        void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
    }

Activity父类默认就实现了OnCreateContextMenuListener接口。

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2,
            Window.Callback, KeyEvent.Callback,
            OnCreateContextMenuListener, ComponentCallbacks2,
            Window.OnWindowDismissedCallback, WindowControllerCallback,
            AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
            ...
    }

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w