PopupMenu作为弹出菜单是很好用的,但是默认只能弹出在view的下方,而实际中这样的弹出位置可能无法满足需求,比如自定义的canvasView,要在canvasView长按的位置弹出菜单,PopupMenu只有一个show的方法,没有可以设置位置的方法,但当我们跟进源码去看时发现了这样的一段代码:

PopupMenu.class

public void show() {this.mPopup.show();}

再对mPopup.show跟踪时进入到了MenuPopupHelper,又有如下的代码

  public void show() {if (!this.tryShow()) {throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");}}public void show(int x, int y) {if (!this.tryShow(x, y)) {throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");}}public boolean tryShow() {if (this.isShowing()) {return true;} else if (this.mAnchorView == null) {return false;} else {this.showPopup(0, 0, false, false);return true;}}

this.mPopup.show调用的是tryShow,而tryShow又调用的是showPopup,在showPopup的参数中有传入xOffset和yOffset,这说明里面是有传偏移量的,再仔细看MenuPopupHelper的show函数发现有show(x,y)的重载,如果我们能调用show(x,y),可能就能满足需求。

但MenuPopupHelper又没办法直接得到,是包装到PopupMenu中的,于是我们采用反射的方式来获取,代码如下

  Field field = popupMenu.getClass().getDeclaredField("mPopup");field.setAccessible(true);MenuPopupHelper helper = (MenuPopupHelper) field.get(popupMenu);helper.show(x, y);

通过反射是得到了MenuPopupHelper,但是会提示错误MenuPopupHelper.show can only be called from within the same library group (groupId=com.android.support),跟入到MenuPopupHelper类里面,可以看到有如下图的限定

为此,我们需要将刚刚反射的部分特别的封装到一个方法中,并在方法上加入@SuppressLint("RestrictedApi"),这样就可以正常运行了,代码如下

public class MenuWorker implements PopupMenu.OnMenuItemClickListener
{@SuppressLint("RestrictedApi")private void showPopupMenu(int x, int y) {if (!_drawActivity.isEditing()) {return;}//创建弹出式菜单对象(最低版本11)PopupMenu popupMenu = new PopupMenu(_drawActivity, _view);//第二个参数是绑定的那个view,菜单弹出时默认是显示该view下方的。initMenu(popupMenu.getMenu());//绑定菜单项的点击事件popupMenu.setOnMenuItemClickListener(this);//显示//popupMenu.show();//默认显示在view的下方,如果要控制具体显示位置,需要使用反射来实现。try {Field field = popupMenu.getClass().getDeclaredField("mPopup");field.setAccessible(true);MenuPopupHelper helper = (MenuPopupHelper) field.get(popupMenu);y = y - _view.getHeight();//如果y取的是触摸点的位置,可能需要作此处理,经测试android5.1的设备会弹窗在屏幕之外helper.show(x, y);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}/*** 初始化菜单** @param menu*/public void initMenu(Menu menu) {menu.clear();menu.add(1, 10001, 0, "添加");menu.add(1, 10002, 1, "删除");menu.add(1, 10003, 2, "切换");}/*** 菜单点击** @param menuItem* @return*/@Overridepublic boolean onMenuItemClick(MenuItem menuItem) {switch (menuItem.getItemId()) {case 10001: {//添加break;}case 10002: {//删除break;}case 10003: {//切换;break;}default:break;}return false;}
}

转载请注明出处

PopupMenu弹出位置的控制相关推荐

  1. showdialog wpf 如何关闭_WPF用ShowDialog()弹出窗体时控制该窗体的显示位置,并传值回父窗体...

    原文:http://blog.csdn.net/kiss0622/article/details/5852153 方法一: 1.父窗口代码 Window1.xaml.cs private void B ...

  2. Winform窗口弹出位置控制

    Winform窗口弹出位置控制 窗体的弹出位置可以由属性StartPosition来指定,默认值有: Manural 自定义,由属性Location指定: CenterScreen 屏幕中央: Win ...

  3. Winform窗口弹出位置设置

    Winform窗口弹出位置控制 窗体的弹出位置可以由属性StartPosition来指定,默认值有: Manural 自定义,由属性Location指定: CenterScreen 屏幕中央: Win ...

  4. win7如何设置某个软件不弹出用户账户控制

    手动修改注册表: 在 HKEY_CURRENT_USERS\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 键下面 ...

  5. layer弹窗弹出位置不在浏览器窗口居中的问题的解决方法

    layer弹窗弹出位置不在浏览器窗口居中的问题的解决方法 参考文章: (1)layer弹窗弹出位置不在浏览器窗口居中的问题的解决方法 (2)https://www.cnblogs.com/chaoyu ...

  6. 禁用计算机账户控制,win8系统禁止弹出用户账户控制窗口的方法

    有不少win8系统用户在运行一些软件程序的时候,发现Windows总是会自动弹出用户账户控制窗口,虽然可以有效防止有害程序更改计算机设置,但是对于一些可信任的程序来说就多余了,那么要win8系统如何禁 ...

  7. android popupmenu 动态添加,Android PopupMenu弹出菜单的实现

    Android PopupMenu弹出菜单的实现 (1)布局文件:用于弹出菜单的处罚button: xmlns:tools="http://schemas.android.com/tools ...

  8. win8 必须重新启动计算机才能关闭用户账户控制,win8系统禁止弹出用户账户控制窗口的方法...

    有不少用户在运行一些软件程序的时候,发现Windows总是会自动弹出用户账户控制窗口,虽然可以有效防止有害程序更改计算机设置,但是对于一些可信任的程序来说就多余了,那么要 1.在运行程序时,当弹出&q ...

  9. 组策略 计算机 用户账户控制,Win10系统总是弹出用户账户控制提示是否允许程序修改计算机的解决方法...

    Win10系统总是弹出用户账户控制提示"是否允许程序修改计算机"的解决方法 不少使用Win10系统的用户都会遇到这样一个问题:当我们打开程序时,系统总会弹出"你要允许以下 ...

最新文章

  1. Linux Crontab 定时任务 命令详解
  2. Android Studio(十二):打包多个发布渠道的apk文件
  3. 电脑字体模糊_2020年初电脑配件和配置单推荐!
  4. Java黑皮书课后题第8章:*8.26(行排序)用下面的方法实现一个二维数组中的行排序。返回新数组,且原数组保持不变。编写一个测试程序,提示用户输入一个3*3的double型矩阵,显示一个排好的矩阵
  5. MybatisPlus实现自动填充
  6. SSIS常用的包—大量插入任务(Bulk Insert task)
  7. Python学习16 正则表达式2 re模块
  8. android中svn插件安装,AndroidSDK安装SVN插件问题解决
  9. python f string slash_python-django中的APPEND_SLASH实现
  10. linux vi编辑撤销,vi撤销命令(u和U),撤销上一次的操作
  11. Building Autoencoders in Keras
  12. 用百度人工智能进行繁体文字中文OCR识别
  13. Android:实现应用版本更新
  14. Bash 编程易犯的错误大全
  15. 谷歌浏览器截取长屏幕(全屏截图)
  16. 2022年上半年软件设计师下午真题试题(案例分析)及答案
  17. APP支付如何对接合适的支付通道?
  18. C标准库头文件—ctype.h
  19. outlook移动ost邮箱数据到D盘
  20. 指南:使用 Trickle 限制应用程序带宽占用

热门文章

  1. Androi--内容提供器
  2. 《人工智能原理》读书笔记:第1章 绪论
  3. 彻底解决微软EDGE浏览器新建标签页后出现Bing搜索框
  4. 文件服务器禁用u盘复制数据,如何禁止U盘拷贝
  5. windows2012R2安装Microsoft Visual C++ 2015 Redistributable报错,提示0x80240017错误代码
  6. 整除理论与线性丢番图方程相关
  7. 智库大会 | 高端对话:智能科技推动管理学变革...
  8. Java jdt 编辑_JDT:打开Java编辑器并显示特定成员
  9. ch3 系统总线(一)
  10. 工程师如何对待开源 | 一个老工程师的肺腑之言