在日常开发中,长按某个view出现个菜单是很常见的需求,Google 也给我们提供了一些组件来实现,比如PopupMenu。但是在实际使用中还是发现他无法满足我们的所有需求。
比如:产品要求长按菜单出现在手指按下的位置,额 这就头疼了,PopupMenu只能展示在view的底部或者头部。还有个问
题如果你的view过长超过一屏,那么 PopupMenu 就无法显示在屏幕里了。
所以没办法,只能硬着头皮自己撸一个menu了。 在日常使用中发现微信的 弹窗菜单 很符合要求,所以就模仿微信来撸一个了。
实现思路
继承
PopupWindow
来实现长按弹窗获取当前按下 位置,传给 view 来显示
具体实现
- 第一个很好实现,我用的是recyclerView 来实现布局的,而且传入的资源是
menu
。而且另一个好处就是控制某些item
的可见(因为我自己项目中有这样需求,所以考虑进去了)
private Menu mMenu;
@NonNull
@SuppressLint("RestrictedApi")
public Menu getMenu() {
if (mMenu == null) {
mMenu = new MenuBuilder(mContext);
}
return mMenu;
}
@NonNull
public MenuInflater getMenuInflater() {
return new MenuInflater(mContext);
}
public void inflate(@MenuRes int menuRes) {
getMenuInflater().inflate(menuRes, getMenu());
}
然后就是填充数据到recyclerView中了
- 第二个需求,就需要在调用的
Activity
中重写dispatchTouchEvent
获取当前点击位置,然后传给 menu 来判断显示位置了
private Point mPoint = new Point();
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mPoint.x = (int) ev.getRawX();
mPoint.y = (int) ev.getRawY();
}
return super.dispatchTouchEvent(ev);
}
public void showPopup(View anchorView, int x, int y) {
if (!getMenu().hasVisibleItems()) {
return;
}
//set visible item data
int size = getMenu().size();
mMenuItems.clear();
for (int i = 0; i < size; i++) {
MenuItem item = getMenu().getItem(i);
if (item.isVisible()) {
mMenuItems.add(item);
}
}
mMenuAdapter.notifyDataSetChanged();
//show
int menuHeight = Display.dip2px(mContext, DEFAULT_ITEM_HEIGHT * mMenuItems.size());
if (x <= mScreenPoint.x / 2) {
if (y + menuHeight < mScreenPoint.y) {
setAnimationStyle(R.style.Animation_top_left);
showAtLocation(anchorView, ANCHORED_GRAVITY, x + X_OFFSET, y);
} else {
setAnimationStyle(R.style.Animation_bottom_left);
showAtLocation(anchorView, ANCHORED_GRAVITY, x + X_OFFSET, y - menuHeight);
}
} else {
if (y + menuHeight < mScreenPoint.y) {
setAnimationStyle(R.style.Animation_top_right);
showAtLocation(anchorView, ANCHORED_GRAVITY, x - mMenuWidth - X_OFFSET, y);
} else {
setAnimationStyle(R.style.Animation_bottom_right);
showAtLocation(anchorView, ANCHORED_GRAVITY, x - mMenuWidth + X_OFFSET, y - menuHeight);
}
}
}
效果如下
大致思路就是这样,最后奉上 源码,你的点赞是对我最大的支持