高版本sdk中PopupMenu包方法出現(xiàn)了變化穴店,此文章未必適用
默認(rèn)情況下撕捍,PopupMenu顯示在指定view的上方或下方,但當(dāng)view的高度太大時會出現(xiàn)下面一種情況泣洞,PopupMenu被擠到最邊上并且顯示不全忧风。微信的效果則是顯示在點(diǎn)擊坐標(biāo)上彈出。但是PopupMenu沒有設(shè)定坐標(biāo)的方法
通過源碼發(fā)現(xiàn)PopupMenu.show()方法會執(zhí)行mPopup.show()球凰。mPopup為MenuPopupHelper類型狮腿,再進(jìn)入MenuPopupHelper的show方法,發(fā)現(xiàn)下面還有一個show(int x,int y)方法呕诉。所以可以通過反射調(diào)用此方法指定PopupMenu的彈出坐標(biāo)缘厢。
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");
}
}
在反射時,一開始是這么寫的甩挫。但是出現(xiàn)了類型轉(zhuǎn)換錯誤,并且無法導(dǎo)入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
具體實(shí)現(xiàn)捶闸,通過反射調(diào)用show(int x,int y)方法。并通過activity的dispatchTouchEvent獲取點(diǎn)擊的坐標(biāo)拖刃。
@Override
public void onLongClick(View view) {
//通過反射删壮,顯示在點(diǎn)擊的位置
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在屏幕上的坐標(biāo)
view.getLocationInWindow(position);
x = (x - position[0]);
y = (y - position[1] - view.getHeight());
show.invoke(o, x, y);
} catch (Exception e) {
e.printStackTrace();
//出錯時調(diào)用普通show方法
popupMenu.show();
}
}
//長按消息彈出刪除框,根據(jù)activity的touchEvent計算,x y 軸坐標(biāo)央碟,刪除框在點(diǎn)擊的坐標(biāo)顯示
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);
}