In daily development, it is common to long press a view to display a menu. Google also provides us with some components to achieve this, such as PopupMenu. But in the actual use or found that it can not meet all our needs.

For example, the product requires the long press menu to appear at the finger position, which is a headache. PopupMenu can only be displayed at the bottom or head of the view. Another problem is that if your view is too long for more than one screen, PopupMenu will not appear on the screen.

So there is no way, can only be forced to scalp themselves a menu. In daily use, I found that the pop-up menu of wechat met the requirements very well, so I imitated wechat to masturbate.

Implementation approach

  • Inherit PopupWindow to implement the long – press popover

  • Gets the current press position and passes it to the view to display

The specific implementation

  • The first one is very good implementation, I use recyclerView to achieve the layout, and the incoming resource ismenu. And the other benefit is to control someitem(Because I have such a need in my own project, so I took it into consideration)
	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());
    }
Copy the code

Then it’s time to populate the data into recyclerView


  • The second requirement needs to be calledActivityThe rewritedispatchTouchEventGet the current click position, and then pass to menu to judge the display position
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);
    }
Copy the code
    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); }}}Copy the code

Results the following

This is the general idea, finally here is the source code, if you think it is useful to you, welcome to like