PopupMenu的弹出坐标设置

高版本sdk中PopupMenu包方法出现了变化,此文章未必适用

默认情况下,PopupMenu显示在指定view的上方或下方,但当view的高度太大时会出现下面一种情况,PopupMenu被挤到最边上并且显示不全。微信的效果则是显示在点击坐标上弹出。但是PopupMenu没有设定坐标的方法

PopupMenu被挤到最边上


通过源码发现PopupMenu.show()方法会执行mPopup.show()。mPopup为MenuPopupHelper类型,再进入MenuPopupHelper的show方法,发现下面还有一个show(int x,int y)方法。所以可以通过反射调用此方法指定PopupMenu的弹出坐标。

PopupMenu.class

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


MenuPopupHelper.class

public void show() {
        if (!tryShow()) {
            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
        }
    }

    public void show(int x, int y) {
        if (!tryShow(x, y)) {
            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
        }
    }



在反射时,一开始是这么写的。但是出现了类型转换错误,并且无法导入com.android.internal.view.menu.MenuPopupHelper这个包。后面通过直接获取方法解决了。


Field mPopup = popupMenu.getClass().getDeclaredField("mPopup");
mPopup.setAccessible(true);
MenuPopupHelper menuPopupHelper = (MenuPopupHelper) mPopup.get(popupMenu);

//java.lang.ClassCastException: com.android.internal.view.menu.MenuPopupHelper cannot be cast to android.support.v7.view.menu.MenuPopupHelper


具体实现,通过反射调用show(int x,int y)方法。并通过activity的dispatchTouchEvent获取点击的坐标。

    @Override
    public void onLongClick(View view) {
        //通过反射,显示在点击的位置
        try {
            Field mPopup = popupMenu.getClass().getDeclaredField("mPopup");
            mPopup.setAccessible(true);
            Object o = mPopup.get(popupMenu);
            Method show = o.getClass().getMethod("show", int.class, int.class);
            int[] position = new int[2];
            //获取view在屏幕上的坐标
            view.getLocationInWindow(position);
            x = (x - position[0]);
            y = (y - position[1] - view.getHeight());
            show.invoke(o, x, y);
        } catch (Exception e) {
            e.printStackTrace();
             //出错时调用普通show方法
            popupMenu.show();
        } 
   }
    


   //长按消息弹出删除框,根据activity的touchEvent计算,x y 轴坐标,删除框在点击的坐标显示
   int x = 0;
   int y = 0;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            x = (int) ev.getRawX();
            y = (int) ev.getRawY();
        }
        return super.dispatchTouchEvent(ev);
    }


最终效果

你可能感兴趣的:(PopupMenu的弹出坐标设置)