Popup Menu

In android, PopupMenu displays a list of items in a modal popup window that is anchored to the view. The PopupMenu will appear below the view if there is a room or above the view in case if there is no space and it will be closed automatically when we touch outside of the popup.

The android Popup Menu provides an overflow style menu for actions that are related to specific content.

We will create a RecyclerView example to explain PopupMenu. Let's create res/menu/context_menu.xml first:

res/menu/context_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/ctxMnuCopy"
        android:title="Copy" />

    <item
        android:id="@+id/ctxMnuPaste"
        android:title="Paste" />

    <item
        android:id="@+id/ctxMnuDelete"
        android:icon="@android:drawable/ic_delete"
        android:title="Delete" />

</menu>

Now let's create PopupMenuAdapter.java:

package com.theitbulls.contextmenuex;

import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.view.menu.MenuPopupHelper;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.view.GravityCompat;
import androidx.recyclerview.widget.RecyclerView;

import java.lang.reflect.Field;

public class PopupMenuAdapter extends RecyclerView.Adapter {
    private final String[] items;

    public PopupMenuAdapter(String[] items) {
        this.items = items;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
        final MyViewHolder viewHolder = (MyViewHolder) holder;

        viewHolder.tvName.setText(items[position]);
        viewHolder.tvMnu.setOnClickListener(new MyClickListner(position));
    }

    @Override
    public int getItemCount() {
        return items.length;
    }

    @Override
    public void onViewRecycled(RecyclerView.ViewHolder holder) {
        holder.itemView.setOnLongClickListener(null);
        super.onViewRecycled(holder);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public final AppCompatTextView tvName;
        public final AppCompatTextView tvMnu;

        public View itemView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            tvName = itemView.findViewById(R.id.tvName);
            tvMnu = itemView.findViewById(R.id.tvMnu);
            this.itemView = itemView;
        }
    }

    private class MyClickListner implements View.OnClickListener {
        private int position;

        public MyClickListner(int position) {
            this.position = position;
        }

        @Override
        public void onClick(final View view) {
            PopupMenu popup = new PopupMenu(view.getContext(), view);

            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.ctxMnuCopy:
                            Toast.makeText(view.getContext(), "You select Copy for: " + items[position], Toast.LENGTH_SHORT).show();
                            return true;
                        case R.id.ctxMnuPaste:
                            Toast.makeText(view.getContext(), "You select Paste for: " + items[position], Toast.LENGTH_SHORT).show();
                            return true;
                        case R.id.ctxMnuDelete:
                            Toast.makeText(view.getContext(), "You select Delete for: " + items[position], Toast.LENGTH_SHORT).show();
                            return true;
                    }
                    return false;
                }
            });
            // here you can inflate your menu
            popup.inflate(R.menu.context_menu);
            popup.setGravity(GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK);

            // if you want icon with menu items then write this try-catch block.
            try {
                Field mFieldPopup = popup.getClass().getDeclaredField("My Popup");
                mFieldPopup.setAccessible(true);
                MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popup);
                mPopup.setForceShowIcon(true);
            } catch (Exception e) {

            }
            popup.show();
        }
    }
}


Now create PopupMenuActivity.java:

package com.theitbulls.contextmenuex;

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class PopupMenuActivity extends AppCompatActivity {
    public static final String[] values = new String[]{"Mango", "Orange", "Apple", "Grapes", "Papaya"};
    private RecyclerView rvListView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.context_menu_activity);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        rvListView = findViewById(R.id.recyclerListView);
        rvListView.setLayoutManager(layoutManager);
        rvListView.setAdapter(new PopupMenuAdapter(values));
    }
}


Now at last layout/context_menu_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.appcompat.widget.LinearLayoutCompat>


Download: Context Menu & Popup Menu Example