How to get RecyclerView position from PopupMenu onMenuItemClick

2k views Asked by At

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;
    }


}
3

There are 3 answers

1
Mahonster On BEST ANSWER

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!

0
gaara87 On

Firstly, in the code snippet you've shown, it doesn't correlate with the available image.

Please provide your onBindViewHolder code. That is where the menu item's on click listener should be set.

0
Adnan Bashir On

Hello dear you need to use this way in adapter

  @Override
    public void onBindViewHolder(@NonNull final RecentPlayedAdapter.MyViewHolder holder, final int position) {
        holder.menudotes.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
PopupMenu popupMenu=new PopupMenu(context, holder.menudotes, Gravity.START);
                    popupMenu.getMenuInflater().inflate(R.menu.popupmenu1,popupMenu.getMenu());
                    popupMenu.show();
                    popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {
                            switch (item.getItemId()) {
                                case R.id.download:
                                    Toast.makeText(context, "Download", Toast.LENGTH_SHORT).show();
                                    //Do position specific action with int position
                                    break;
                                case R.id.playlist:
                                    //Do position specific action with int position
                                    Toast.makeText(context, "Playlist", Toast.LENGTH_SHORT).show();

                                    break;
                                case R.id.share:
                                    //Do position specific action with int position
                                    Toast.makeText(context, "Share", Toast.LENGTH_SHORT).show();


                                    break;
                            }
                            return true;
                        }
                    });
    }
        });
    }