androidandroid-popupwindow

How to get RecyclerView position from PopupMenu onMenuItemClick


Using a RecylcerView, I'm trying to have a popup menu for each item in the list, similar to this:

Popup Menu in Google Play Music playlist.

Creating the popup menu is simple, but how do you get the position of the item clicked in onMenuItemClicked?

public class Activity extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener {

    public void showPopupMenu(View v) {
        PopupMenu popupMenu = new PopupMenu(this, v);
        MenuInflater inflater = popupMenu.getMenuInflater();
        inflater.inflate(R.menu.edit_delete_menu, popupMenu.getMenu());
        popupMenu.show();
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {

        //get position here from RecyclerView here?

        switch (item.getItemId()) {
            case R.id.edit:
            //Do position specific action
            break;
            case R.id.delete:
                //Do position specific action
                break;
        }
        return false;
    }


}

Solution

  • Alright, so I (surprisingly) managed to answer my own question here.

    In order to obtain the position from a RecylcerView adapter within onMenuItemClicked using PopupMenu, I created a custom implementation of PopupMenu.

    Doing so provides much greater flexibility when using PopupMenu, such as displaying icons in your menus.

    Look at Google's source code for PopupMenu, and create your own, something like MyPopupMenu that is exactly the same, but you can modify certain instances of what the class can do.

    To complete my problem, I added an OnClickListener to the More button within my RecyclerView.Adapter. When clicked, the button calls an interface method that passes both the button view, and the adapter's current position.

    In the custom implementation of MyPopupMenu, add the variable requirements for each constructor for an int value. Also add int position to the interface method onMenuItemClick(MenuItem item, int position) within MyPopupMenu.

    Finally, assemble in the activity class.

    public class MyActivity extends AppCompatActivity implements MyAdapter.OnItemEventListener, PopupMenu.OnMenuItemClickListener {
    
        @Override
        public void onMoreClicked(View v, int position) {
            MyPopupMenu popupMenu = new MyPopupMenu(this, v, position);
            MenuInflater inflater = popupMenu.getMenuInflater();
            inflater.inflate(R.menu.edit_delete_menu, popupMenu.getMenu());
            popupMenu.setOnMenuItemClickListener(this);
            popupMenu.show();
        }
    
        @Override
        public boolean onMenuItemClick(MenuItem item, int position) {
            switch (item.getItemId()) {
                case R.id.edit:
                    //Do position specific action with int position
                    break;
                case R.id.delete:
                    //Do position specific action with int position
                    break;
            }
            return false;
        }
    }
    
    class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        private final OnItemEventListener onItemEventListener;
    
        static class ViewHolder extends RecyclerView.ViewHolder {
            ImageButton more;
    
            ViewHolder(View v) {
                super(v);
                more = (ImageButton) v.findViewById(R.id.list_item_more_button);
            }
        }
    
        public NewGameAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
            final ViewHolder viewHolder = new ViewHolder(v);
    
            viewHolder.more.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onItemEventListener.onMoreClicked(viewHolder.more, viewHolder.getAdapterPosition());
                }
            });
    
            return viewHolder;
        }
    
        interface OnItemEventListener {
            void onMoreClicked(View v, int position);
        }
    }
    

    Let me know what you guys think!