Jak stworzyć menu kontekstowe dla RecyclerView

100

Jak zaimplementować menu kontekstowe dla funkcji RecyclerView?Pozornie wywołanie registerForContextMenu(recyclerView)nie działa. Wzywam to z fragmentu. Czy ktoś odniósł sukces, wdrażając to?

Binoy Babu
źródło
Jestem na tej samej łodzi. Wypróbowałem różne oceny ListView za pomocą AdapterContextMenuInfo - ale nie mogę uzyskać informacji. Pozycja
RoundSparrow hilltx
Myślę, że dni menu kontekstowego się skończyły.
Binoy Babu
4
Hej - mam to działające;) refeerence: stackoverflow.com/questions/2321332/… - dla mnie ViewHolder to słuchacz onClick - zrobiłem też z niego OnCreateContextMenuListener. Kluczem do tego wszystkiego jest to, że zdałem sobie sprawę, że tylko JEDNO menu może być otwarte na raz - więc adapter potrzebuje tylko informacji int, która była ostatnią pozycją na liście RecyclerView, na którą kliknięto menu ... wtedy Fragment / Działanie może zapytaj adapter, kiedy otrzyma faktyczne kliknięcie elementu menu.
RoundSparrow hilltx

Odpowiedzi:

94

Nie można bezpośrednio zaimplementować tych metod, takich jak onClickListener , OnContextMenuListener itp., Ponieważ RecycleView rozszerza android.view.ViewGroup . Więc nie możemy bezpośrednio użyć tej metody. Metody te możemy zaimplementować w klasie adaptera ViewHolder . Z menu kontekstowego w RecycleView możemy skorzystać w następujący sposób:

public static class ViewHolder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {

    TextView tvTitle;
    ImageView ivImage;

    public ViewHolder(View v) {
        super(v);
        tvTitle =(TextView)v.findViewById(R.id.item_title);
        v.setOnCreateContextMenuListener(this);


    }

Teraz postępujemy zgodnie z tą samą procedurą podczas implementacji menu kontekstowego.

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

    menu.setHeaderTitle("Select The Action");    
    menu.add(0, v.getId(), 0, "Call");//groupId, itemId, order, title   
    menu.add(0, v.getId(), 0, "SMS"); 

}

Jeśli masz jakieś trudności, poproś o komentarz.

Prabhakar
źródło
7
Ok, a następnie wdrażamy onContextItemSelectedna poziomie aktywności / fragmentu. getTitledziała, getItemIddziała, ale getMenuInfodostarcza null. Jak więc zdobyć ViewHolder?
Michael Schmidt
@MichaelSchmidt może u pokazać mi swój kod, w którym zaimplementujesz informacje z menu kontekstowego.
Prabhakar,
7
Po pewnym eksperymentowaniu również nie mogę tego uruchomić, getMenuInfo()zwraca wartość null in onContextItemSelected(). Może zdarzyło się, że osoby, które sprawiły, że to zadziałało, mają onCreateContextMenu()metodę na wyższym szczeblu hierarchii ( RecyclerViewlub Fragment)? To może zadziałać, ale następnie prowadzi nas do innych odpowiedzi na to pytanie.
NeilS
3
Prabhakbar, nie wspomniałeś, jak zdobyć kliknięty przedmiot ani widok?
Benjamin Stürmer
6
Możesz użyć menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");a następnie w swoim teście metody wywołania zwrotnego, item.getGroupId()aby uzyskać pozycję
JacobPariseau
102

Dzięki za informacje i komentarze. Udało mi się osiągnąć ContextMenuza przedmioty w Recyclerview.

Oto co zrobiłem

w onViewCreatedmetodzie fragmentu lub metodzie działania onCreate:

registerForContextMenu(mRecyclerView);

Następnie w Adapter dodaj

private int position;

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

spraw, aby ViewHolderklasa implementowałaOnCreateContextMenuListener

public static class ViewHolder extends RecyclerView.ViewHolder 
        implements View.OnCreateContextMenuListener {

    public ImageView icon;

    public TextView fileName;
    public ImageButton menuButton;


    public ViewHolder(View v) {
        super(v);
        icon = (ImageView)v.findViewById(R.id.file_icon);
        fileName = (TextView)v.findViewById(R.id.file_name);
        menuButton = (ImageButton)v.findViewById(R.id.menu_button);
        v.setOnCreateContextMenuListener(this);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, 
        ContextMenu.ContextMenuInfo menuInfo) {
        //menuInfo is null
        menu.add(Menu.NONE, R.id.ctx_menu_remove_backup, 
            Menu.NONE, R.string.remove_backup);
        menu.add(Menu.NONE, R.id.ctx_menu_restore_backup,
            Menu.NONE, R.string.restore_backup);
    }
}

onBindViewHoldermethod add OnLongClickListeneron the holder.itemView, aby przechwycić pozycję przed załadowaniem menu kontekstowego:

holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        setPosition(holder.getPosition());
        return false;
    }
});

Następnie onViewRecycledusuń Listener, aby nie było problemów z odwołaniami. (może nie być wymagane).

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

Na koniec we fragmencie / działaniu zastąp onContextItemSelectedjak poniżej:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = -1;
    try {
        position = ((BackupRestoreListAdapter)getAdapter()).getPosition();
    } catch (Exception e) {
        Log.d(TAG, e.getLocalizedMessage(), e);
        return super.onContextItemSelected(item);
    }
    switch (item.getItemId()) {
        case R.id.ctx_menu_remove_backup:
            // do your stuff
            break;
        case R.id.ctx_menu_restore_backup:
            // do your stuff
            break;
    }
    return super.onContextItemSelected(item);
}
Hardik Shah
źródło
1
position = ((BackupRestoreListAdapter) getAdapter ()). getPosition (); -> get error: Metoda getAdapter () jest niezdefiniowana dla typu ..., czy możesz pokazać metodę
getAdapter
1
Świetna sugestia, dziękuję. Mniejszy: parametr viewHolder.getPosition () jest przestarzały. Jaka jest Twoja rada dotycząca ulepszeń?
tm1701
10
użyj viewHolder.getAdapterPosition () zamiast getPosition ()
Sagar Chavada
2
W przypadku tych, którzy otrzymali błąd getAdapter (), rozwiązałem go, zapisując odwołanie do mojego RecyclerView, a następnie używam go w ten sposób: ((BackupRestoreListAdapter) recyklerView.getAdapter ()). GetPosition ();
Kevin Amorim,
1
A gdzie dokładnie jest R.id.ctx_menu_remove_backup?
akubi
29

Obecna odpowiedź jest nieprawidłowa. Oto działająca implementacja:

public class ContextMenuRecyclerView extends RecyclerView {

  private RecyclerViewContextMenuInfo mContextMenuInfo;

  @Override
  protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return mContextMenuInfo;
  }

  @Override
  public boolean showContextMenuForChild(View originalView) {
    final int longPressPosition = getChildPosition(originalView);
    if (longPressPosition >= 0) {
        final long longPressId = getAdapter().getItemId(longPressPosition);
        mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
        return super.showContextMenuForChild(originalView);
    }
    return false;
  }

  public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {

    public RecyclerViewContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
  }
}

W swoim fragmencie (lub działaniu):

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecyclerView = view.findViewById(R.id.recyclerview);
    registerForContextMenu(mRecyclerView);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    // inflate menu
    MenuInflater inflater = getActivity().getMenuInflater();
    inflater.inflate(R.menu.my_context_menu, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    return super.onContextItemSelected(item);
    RecyclerViewContextMenuInfo info = (RecyclerViewContextMenuInfo) item.getMenuInfo();
    // handle menu item here
}

I na koniec w Twoim ViewHolder:

class MyViewHolder extends RecyclerView.View.ViewHolder {
    ...
    private void onLongClick() {
        itemView.showContextMenu();
    }
}
Renaud Cerrato
źródło
Proszę, dodaj konstruktor RecyclerView, który musiałeś zaimplementować na yout ContextMenuRecyclerView. Ponadto getChildPosition()jest teraz przestarzały. getChildAdapterPosition()Zamiast tego użyłem .
Juan José Melero Gómez
1
Uwaga: Przepraszamy, zapomniałem dodać: getChildPosition()jest przestarzałe w com.android.support:recyclerview-v7:22.0.0.
Juan José Melero Gómez
1
to nie działa. nie możesz uzyskać dostępu do getView (). showContextMenu () z RecyclerView.View.ViewHolder.
Mulgard,
4
To działa dla mnie. Ale nie ma potrzeby mieć onLongClick () w MyViewHolder, wystarczy ustawić itemView.setLongClickable (true) w konstruktorze, pojawi się menu kontekstowe, gdy OnLongClickListener nie jest zarejestrowany.
olchy
2
Ważne również: podczas rozszerzania RecyclerView do ContextMenuRecyclerView, nie zapomnij DODAĆ KONSTRUKTORÓW sugerowanych przez IDE. W szczególności, jeśli nie zaimplementujesz konstruktora z dwoma argumentami, który pobiera Context i AttributeSet, system Android nie będzie w stanie zawyżać kodu XML układu.
lidkxx
24

Spróbuj tego dla Viewelementu w recycleView

.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.add("delete").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {

                    //do what u want
                    return true;
                }
            });
        }
    });

Możesz go używać do ustawiania danych do ViewHolderelementu

Sergey Bondarenko
źródło
Dokładnie to, czego potrzebowałem do menu kontekstowego w widoku obrazu w widoku z recyklingu
Themos
2
Dla każdego, kto patrzy na to teraz, działa to tylko w API 23 i nowszych.
SWoo
16

Odpowiedź Prabhakara jest poprawna, ale nie wyjaśnił, jak uzyskać dane związane z wciśniętym elementem, gdy wybrana jest pozycja menu kontekstowego. Możemy użyć onContextItemSelectedwywołania zwrotnego, ale w tym przypadku ContextMenuInfonie jest on dostępny ( null) (jeśli getContextMenuInfo()metoda nie jest nadpisana dla widoku tłoczonego). Najprostszym rozwiązaniem jest więc dodanie OnMenuItemClickListenerbezpośrednio do pliku MenuItem.

private class ViewHolder extends RecyclerView.ViewHolder {
    private final TextView mTitleTextView;
    private MyItemData mData;

    public ViewHolder(View view) {
        super(view);

        mTitleTextView = (TextView)view.findViewById(R.id.title);

        view.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
    }

    public void bind(@NonNull MyItemData data) {
         mData = data;

         String title = mData.getTitle();
         mTitleTextView.setText(title);
    }

    private final View.OnCreateContextMenuListener mOnCreateContextMenuListener = new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            if (mData!= null) {
                MenuItem myActionItem = menu.add("My Context Action");
                myActionItem.setOnMenuItemClickListener(mOnMyActionClickListener);
            }
        }
    };

    private final MenuItem.OnMenuItemClickListener mOnMyActionClickListener = new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            //todo: process item click, mData is available here!!!
            return true;
        }
    };
}
Valeriy Katkov
źródło
1
Wyjaśnij jasno, co robi Twój fragment kodu i jak. Sam kod wklejony do kopii nie wystarczy, nawet jeśli jest wartościowy.
peterh - Przywróć Monikę
Wydaje się, że jest to rozsądny kompromis, jeśli nie chcesz tworzyć niestandardowych podklas RecyclerViewtylko po to, aby przesłonić getContextMenuInfoitp., Nawet jeśli nie jest to tak wydajne, jak pozwolenie fragmentowi / aktywności na obsługę kliknięć. Słuchacze będą mieli dostęp do danych w uchwycie, więc nie potrzebujesz pozycji. Teoretycznie i tak można buforować pozycję po powiązaniu w adapterze i użyć delegacji do wywołania swojego posiadacza, jeśli trzeba, chociaż Contextczasami wystarczy użyć jednego z powiązanych widoków.
qix
10

Odpowiedź @ Renaud zadziałała dla mnie, ale najpierw wymagała kilku poprawek kodu. To tak, jakby zamieścił fragmenty z kilku różnych iteracji swojego kodu. Zmiany, które należy wprowadzić, to:

  • RecyclerContextMenuInfoi RecyclerViewContextMenuInfonależą do tej samej klasy. Wybierz imię i trzymaj się go.
  • ViewHolderMusi wdrożyć View.OnLongClickListener, i pamiętaj, aby zadzwonić setOnLongClickListener()na pozycję w konstruktorze.
  • W onLongClick()słuchaczu getView().showContextMenu()jest całkowicie błędny. Musisz zadzwonić, showContextMenuForChild()w ContextMenuRecyclerViewprzeciwnym razie ContextMenuInfowejdziesz onCreateContextMenu()i onContextItemSelected()będzie zerowe.

Mój edytowany kod poniżej:

ContextMenuRecyclerView:

public class ContextMenuRecyclerView extends RecyclerView {

    private RecyclerViewContextMenuInfo mContextMenuInfo;

    @Override
    protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
        return mContextMenuInfo;
    }

    @Override
    public boolean showContextMenuForChild(View originalView) {
        final int longPressPosition = getChildPosition(originalView);
        if (longPressPosition >= 0) {
            final long longPressId = getAdapter().getItemId(longPressPosition);
                mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
            return super.showContextMenuForChild(originalView);
        }
        return false;
    }

    public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {

        public RecyclerViewContextMenuInfo(int position, long id) {
            this.position = position;
            this.id = id;
        }

        final public int position;
        final public long id;
    }
}

W twoim fragmencie:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecyclerView = view.findViewById(R.id.recyclerview);
    registerForContextMenu(mRecyclerView);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    // inflate menu here
    // If you want the position of the item for which we're creating the context menu (perhaps to add a header or something):
    int itemIndex = ((ContextMenuRecyclerView.RecyclerViewContextMenuInfo) menuInfo).position;
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    ContextMenuRecyclerView.RecyclerViewContextMenuInfo info = (ContextMenuRecyclerView.RecyclerViewContextMenuInfo) item.getMenuInfo();
    // handle menu here - get item index or ID from info
    return super.onContextItemSelected(item);
}

W Twoim ViewHolder:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {

    public MyViewHolder( View itemView ) {
        super( itemView );
        itemView.setOnLongClickListener( this );
    }

    @Override public boolean onLongClick() {
        recyclerView.showContextMenuForChild( v );
        return true;
    }
}

Ponadto, upewnij się, że zastąpienie RecyclerViewze ContextMenuRecyclerVieww układzie!

josh2112
źródło
1
Dzięki @ josh2112 za wskazanie mi się literówki, po prostu je skorygować - ALE dotyczące ostatniego punktu, można zastąpić recyclerView.showContextMenuForChild(itemView);przez itemView.showContextMenu().
Renaud Cerrato,
1
Ważne również: rozszerzając RecyclerView do ContextMenuRecyclerView, nie zapomnij DODAĆ KONSTRUKTORÓW sugerowanych przez IDE. W szczególności, jeśli nie zaimplementujesz konstruktora z dwoma argumentami, który pobiera Context i AttributeSet, system Android nie będzie w stanie zawyżać kodu XML układu.
lidkxx
7

Oto przejrzysty sposób używania kontekstu menu w elementach RecyclerView

Po pierwsze, potrzebujesz pozycji przedmiotu

W klasie adaptera:

 /**
 * Custom on long click item listener.
 */
onLongItemClickListener mOnLongItemClickListener;

public void setOnLongItemClickListener(onLongItemClickListener onLongItemClickListener) {
    mOnLongItemClickListener = onLongItemClickListener;
}

public interface onLongItemClickListener {
    void ItemLongClicked(View v, int position);
}

W onBindViewHolderhook the custom listener:

        // Hook our custom on long click item listener to the item view.
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (mOnLongItemClickListener != null) {
                    mOnLongItemClickListener.ItemLongClicked(v, position);
                }

                return true;
            }
        });

W MainActivity (Activity / Fragment) utwórz pole:

private int mCurrentItemPosition;

W obiekcie Adapter ustaw niestandardowy odbiornik:

    mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
        @Override
        public void ItemLongClicked(View v, int position) {
            mCurrentItemPosition = position;
        }
    });

Teraz masz pyszną pozycję dla każdego elementu, który od dawna na niego klikałeś 😋

Po drugie, stwórz swoje menu

W res -> menu Utwórz plik zawierający pozycję menu context_menu_main.xml:

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

W MainActivity: Zaimplementuj oba onCreateContextMenui onContextItemSelected:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.context_menu_main, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.delete) {

    }

    if (id == R.id.share) {

    }

    return true;
}

Po trzecie, wróć do obiektu Adapter

  1. Zarejestruj swoje menu kontekstowe.
  2. pokaż menu kontekstowe.

    registerForContextMenu(mRecyclerView);
    mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
        @Override
        public void ItemLongClicked(View v, int position) {
            mCurrentItemPosition = position;
            v.showContextMenu();
        }
    });
    

Mam nadzieję, że niczego nie zapomnę 🤔

Więcej informacji w dokumentacji menu

MohammadL
źródło
Dzięki! Jak przekazać dane do menu kontekstowego? Na przykład identyfikator przedmiotu, tekst przedmiotu i tak dalej.
CoolMind
4

Oto prostszy sposób na zrobienie tego z Kotlinem, który zadziałał dla mnie. Głównym wyzwaniem jest ustalenie położenia elementu, który został wciśnięty. Wewnątrz adaptera możesz umieścić ten fragment kodu i będzie on w stanie uchwycić pozycję elementu, dla którego jest wyświetlane menu kontekstowe; to wszystko.

override fun onBindViewHolder(holder: YourViewHolder, position: Int) {

...     

    holder.view.setOnCreateContextMenuListener { contextMenu, _, _ -> 
            contextMenu.add("Add").setOnMenuItemClickListener {
                    longToast("I'm pressed for the item at position => $position")
                    true    
            }       
    }       

} 
Myszka Miki
źródło
2
To najbardziej naturalny i kontrolowany sposób na zrobienie tego
nima
3

Może spóźnię się na imprezę, ale mam działające rozwiązanie . Zrobiłem dla tego sedno.

Dodaj menu kontekstowe do RecyclerView

ActivityName.java

//Import Statements

public class ActivityName extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

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


        //Recycle View
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mLayoutManager = new LinearLayoutManager(getApplicationContext());
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new BirthdaysListAdapter(data, this);
        mRecyclerView.setAdapter(mAdapter);


    }

RecyclerAdapter.java

//Import Statements


public class BirthdaysListAdapter extends RecyclerView.Adapter<BirthdaysListAdapter.ViewHolder> {
    static Context ctx;

    private List<typeOfData> Data;


    public BirthdaysListAdapter(List<typeOfData> list, Context context) {
        Data = list;
        this.ctx = context;

    }

    BirthdaysListAdapter() {
    }

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
        public TextView name;
        public TextView Birthday;
        public ImageView colorAlphabet;
        public TextView textInImg;


        public ViewHolder(View v) {
            super(v);
            name = (TextView) v.findViewById(R.id.name);
            Birthday = (TextView) v.findViewById(R.id.Birthday);
            colorAlphabet = (ImageView) v.findViewById(R.id.colorAlphabet);
            textInImg = (TextView) v.findViewById(R.id.textInImg);


            v.setOnCreateContextMenuListener(this); //REGISTER ONCREATE MENU LISTENER
        }

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v                         //CREATE MENU BY THIS METHOD
                                        ContextMenu.ContextMenuInfo menuInfo) {
            new BirthdaysListAdapter().info = (AdapterView.AdapterContextMenuInfo) menuInfo;
            MenuItem Edit = menu.add(Menu.NONE, 1, 1, "Edit");
            MenuItem Delete = menu.add(Menu.NONE, 2, 2, "Delete");
            Edit.setOnMenuItemClickListener(onEditMenu);
            Delete.setOnMenuItemClickListener(onEditMenu);


        }
//ADD AN ONMENUITEM LISTENER TO EXECUTE COMMANDS ONCLICK OF CONTEXT MENU TASK
        private final MenuItem.OnMenuItemClickListener onEditMenu = new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {


                DBHandler dbHandler = new DBHandler(ctx);
                List<WishMen> data = dbHandler.getWishmen();

                switch (item.getItemId()) {
                    case 1:
                        //Do stuff
                        break;

                    case 2:
                       //Do stuff

                        break;
                }
                return true;
            }
        };


    }


    public List<ViewBirthdayModel> getData() {
        return Data;
    }


    @Override
    public long getItemId(int position) {

        return super.getItemId(position);
    }


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

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.name.setText(Data.get(position).getMan().getName());
        holder.Birthday.setText(Data.get(position).getMan().getBday());
        holder.colorAlphabet.setBackgroundColor(Color.parseColor(Data.get(position).getColor()));
        holder.textInImg.setText(String.valueOf(Data.get(position).getMan().getName().toUpperCase().charAt(0)));
           }


    @Override
    public int getItemCount() {
        return Data.size();
    }

    private int position;

    public int getPosition() {

        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

}
Gaurav Sharma
źródło
3

Połączyłem swoje rozwiązanie z rozwiązaniem od @Hardik Shah:

W działalności mam:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    if (v.getId() == R.id.rvQuests) {
        getMenuInflater().inflate(R.menu.list_menu, menu);
    }
}

W Adapterze mam:

private MainActivity context;
private int position;

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

public QuestsAdapter(MainActivity context, List<Quest> objects) {
    this.context = context;
    this.quests.addAll(objects);
}

public class QuestViewHolder extends RecyclerView.ViewHolder {
    private QuestItemBinding questItemBinding;

    public QuestViewHolder(View v) {
        super(v);
        questItemBinding = DataBindingUtil.bind(v);
        v.setOnCreateContextMenuListener(context);
    }
}

@Override
public void onBindViewHolder(final QuestViewHolder holder, int position) {
    Quest quest = quests.get(position);
    holder.questItemBinding.setQuest(quest);
    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            setPosition(holder.getAdapterPosition());
            return false;
        }
    });
}

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

We fragmencie mam:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = ((QuestsAdapter) questsList.getAdapter()).getPosition();
    switch (item.getItemId()) {
        case R.id.menu_delete:
            Quest quest = questsAdapter.getItem(position);
            App.getQuestManager().deleteQuest(quest);
            questsAdapter.remove(quest);
            checkEmptyList();
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}
Szyk
źródło
2

Rozwiązanie dla tych, którzy chcą uzyskać identyfikator przedmiotu podczas dzwonieniaContextMenu .

Jeśli masz RecyclerViewz takimi przedmiotami (zawierającymi klikalne ImageView):

lista

wtedy powinieneś otrzymać oddzwonienie od onClickListener.

Adapter

class YourAdapter(private val contextMenuCallback: ContextMenuCallback) :
    RecyclerView.Adapter<YourAdapter.ViewHolder>() {

    private var items: MutableList<Item> = mutableListOf()

    ...

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        val item = items[position] as Item
        updateItem(viewHolder, item)

        setOnClickListener(viewHolder.itemView, items[position].id, items[position].title)
    }

    private fun setOnClickListener(view: View, id: Int, title: String) {
//        view.setOnClickListener { v ->  }
        // A click listener for ImageView `more`.
        view.more.setOnClickListener {
            // Here we pass item id, title, etc. to Fragment.
            contextMenuCallback.onContextMenuClick(view, id, title)
        }
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val titleTextView: TextView = itemView.title
    }

    class Item(
        val id: Int,
        val title: String
    )

    interface ContextMenuCallback {
        fun onContextMenuClick(view: View, id: Int, title: String)
    }
}

Fragment

class YourFragment : Fragment(), YourAdapter.ContextMenuCallback {

    private var adapter: YourAdapter? = null
    private var linearLayoutManager: LinearLayoutManager? = null
    private var selectedItemId: Int = -1
    private lateinit var selectedItemTitle: String


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        adapter = YourAdapter(this)
        view.recycler_view.apply {
            layoutManager = linearLayoutManager
            adapter = this@YourFragment.adapter
            setHasFixedSize(true)
        }

        registerForContextMenu(view.recycler_view)
    }

    override fun onCreateContextMenu(menu: ContextMenu?, v: View?,
                                     menuInfo: ContextMenu.ContextMenuInfo?) {
        activity?.menuInflater?.inflate(R.menu.menu_yours, menu)
    }

    override fun onContextItemSelected(item: MenuItem?): Boolean {
        super.onContextItemSelected(item)
        when (item?.itemId) {
            R.id.action_your -> yourAction(selectedItemId, selectedItemTitle)
            ...
        }
        return true
    }

    override fun onContextMenuClick(view: View, id: Int, title: String) {
        // Here we accept item id, title from adapter and show context menu.
        selectedItemId = id
        selectedItemTitle = title
        view.showContextMenu()
    }
}

Ostrzeżenie!

Jeśli użyjesz ViewPageropartego na jednym fragmencie (wszystkie strony są podobnymi listami), napotkasz problem. Kiedy nadpisujesz, onContextItemSelectedaby zrozumieć, który element menu został wybrany, otrzymasz identyfikator elementu listy z pierwszej strony! Aby rozwiązać ten problem, zobacz Wrong fragment w ViewPager odbiera wywołanie onContextItemSelected .

CoolMind
źródło
1

Witam, wyszedł z jedną alternatywą, która działa dla mnie. Po prostu rejestruję mój itemView w registerContextMenu i konstruktorze ViewHolder, ustawiam również onLongClikcListener na ten sam widok. W implementacji onLongClick (View v) po prostu otrzymuję klikniętą pozycję za pomocą metody getLayoutPosition () i zapisuję w zmiennej instancji (utworzyłem klasę do reprezentowania tych danych, tak jak oczekuje się, że ContextMenuInfo ma działać), ale ważniejsze jest, aby na pewno zwrócisz false w tej metodzie. Wszystko, co musisz teraz zrobić, jest w tobie na onContextItemSelected (element MenuItem), przeczytaj dane, które przechowujesz w zmiennej instancji i jeśli są prawidłowe, kontynuuj swoje działania. Oto fragment.

  public MyViewHolder(View itemView){
super(itemView);
registerForContextMenu(itemView);
itemView.setOnLongClickListener(this);
}

Sprawiam, że ViewHolder implementuje OnLongClickListener, ale możesz to zrobić w dowolny sposób.

@Override
public boolean onLongClick(View v){
    mCurrentLongItem = new ListItemInfo(v.getId(), getLayoutPosition());
    return false; // REMEMBER TO RETURN FALSE.
  }

Możesz również ustawić to w adapterze lub w innym widoku, który masz w ViewHolder (tj. TextView). Ważna jest implementacja onLongClik ().

@Override
public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()){
        case R.id.client_edit_context_menu:
            if(mCurrentLongItem != null){
                 int position = mCurrentLongItem.position;
                //TAKE SOME ACTIONS.
                mCurrentLongItem = null;
            }
            return true;
    }
    return super.onContextItemSelected(item);
}

Najlepsze jest to, że nadal możesz przetwarzać zdarzenie LongClick zwracające wartość true w przypadkach, w których chcesz, a conextMenu nie pojawi się.

Ta metoda działa, ponieważ registerForContextView sprawia, że ​​View LongClickable, a kiedy nadejdzie czas na przetworzenie ContextMenu, system wywołuje performLongClick, które najpierw wywołuje implementację onLongClick, a jeśli zwróci false, wywoła showContextMenu.

Raziel25
źródło
1

Używam tego rozwiązania już od jakiegoś czasu i działa całkiem nieźle.

public class CUSTOMVIEWNAME extends RecyclerView { 

public CUSTOMVIEWNAME(Context context) {
    super(context);
}

public CUSTOMVIEWNAME (Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CUSTOMVIEWNAME (Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

private RecyclerContextMenuInfo mContextMenuInfo;

@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return mContextMenuInfo;
}

@Override
public boolean showContextMenuForChild(View originalView) {
    final int longPressPosition = getChildAdapterPosition(originalView);
    if (longPressPosition >= 0) {
        final long longPressId = getAdapter().getItemId(longPressPosition);
        mContextMenuInfo = new RecyclerContextMenuInfo(longPressPosition,    `           longPressId);
        return super.showContextMenuForChild(originalView);
    }
    return false;
}

public class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo             {

    public RecyclerContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
}
}

Teraz w swoim fragmencie lub działaniu zaimplementuj następujące metody.

  @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);

    // Inflate Menu from xml resource
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(R.menu.context_menu, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    ContextMenuRecyclerView.RecyclerContextMenuInfo info = (ContextMenuRecyclerView.RecyclerContextMenuInfo) item.getMenuInfo();
    Toast.makeText(InstanceOfContext , " User selected  " + info.position, Toast.LENGTH_LONG).show();

    return false;
}

Na koniec zarejestruj się, aby uzyskać dostęp do menu kontekstowego w widoku recyklingu

   //for showing a popup on LongClick of items in recycler.
    registerForContextMenu(recyclerView);

To powinno działać!

Rakesh Gopathi
źródło
1

Oto jak zaimplementować menu kontekstowe dla RecyclerView i uzyskać pozycję elementu, dla którego wybrano element menu kontekstowego:

public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> {

... 

@Override
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int position) {

    ...

    viewHolder.itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.add(0, R.id.mi_context_disable, 0, R.string.text_disable)
                    .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {
                            // can do something with item at position given below,
                            // viewHolder is final
                            viewHolder.getAdapterPosition();
                            return true;
                        }
                    });
            menu.add(0, R.id.mi_context_remove, 1, R.string.text_remove)
                    .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {                                
                            // can do something with item at position given below,
                            // viewHolder is final
                            viewHolder.getAdapterPosition();
                            return true;
                        }
                    });
        }
    });
}

static class ViewHolder extends RecyclerView.ViewHolder {
    private View itemView;

    private ViewHolder(@NonNull View itemView) {
        super(itemView);
        this.itemView = itemView;
    }
}

}

B-GangsteR
źródło
0

Walczyłem z tym, ponieważ Android nie radzi sobie z tym dobrze dla mnie w RecyclerView, który działał bardzo dobrze dla ListView.

Najtrudniejszym elementem jest to, że element ContextMenuInfo jest osadzony w widoku, którego nie można łatwo dołączyć, poza zastąpieniem widoku.

Będziesz więc potrzebować opakowania, które pomoże Ci dostarczyć informacje o pozycji do działania.

public class RecyclerContextMenuInfoWrapperView extends FrameLayout {
private RecyclerView.ViewHolder mHolder;
private final View mView;

public RecyclerContextMenuInfoWrapperView(View view) {
    super(view.getContext());
    setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    mView = view;
    addView(mView);
}

public void setHolder(RecyclerView.ViewHolder holder) {
    mHolder = holder;
}

@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return new RecyclerContextMenuInfo(mHolder.getPosition(), mHolder.getItemId());
}

public static class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo {

    public RecyclerContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
}

}

Następnie w RecyclerAdapter, podczas tworzenia ViewHolders, musisz ustawić Wrapper jako widok główny i zarejestrować contextMenu w każdym widoku.

public static class AdapterViewHolder extends RecyclerView.ViewHolder {
    public AdapterViewHolder(  View originalView) {
        super(new RecyclerContextMenuInfoWrapperView(originalView);
        ((RecyclerContextMenuInfoWrapperView)itemView).setHolder(this);
        yourActivity.registerForContextMenu(itemView);
        itemView.setOnCreateContextMenuListener(yourListener);
    }

}

I wreszcie, w swojej aktywności będziesz w stanie robić to, co zwykle:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = ((RecyclerContextMenuInfoWrapperView.RecyclerContextMenuInfo)item.getMenuInfo()).position;
    // do whatever you need as now you have access to position and id and everything
Zoro
źródło
0

Najlepszym rozwiązaniem było użycie menu kontekstowego z widokiem recyklera, jeśli utworzysz niestandardowy widok recyklera i zastąpisz getContextMenuInfo()metodę i zwrócisz własne wystąpienie obiektu informacyjnego menu kontekstowego, aby można było pobrać pozycje, gdy zostało utworzone i po kliknięciu menu:

@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return mContextMenuInfo;
}

Spójrz na to, co stworzyłem:

https://gist.github.com/resengupta/2b2e26c949b28f8973e5

ReeSen
źródło
0

Rozwijając nieco niektóre z powyższych odpowiedzi, jeśli chcesz uniknąć ręcznego definiowania menu w swoim kodzie w adapterze / ViewHolder, możesz użyć PopupMenu i uzupełnić opcje menu ze standardowego pliku zasobów menu.xml.

Poniższy przykład pokazuje to, w tym możliwość przekazania odbiornika, który możesz zaimplementować w swoim fragmencie / działaniu, aby reagować na kliknięcia menu kontekstowego.

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {

private List<CustomObject> objects;
private OnItemSelectedListener listener;
private final boolean withContextMenu;

class ViewHolder extends RecyclerView.ViewHolder
        implements View.OnClickListener, View.OnCreateContextMenuListener, PopupMenu.OnMenuItemClickListener {

    @BindView(R.id.custom_name)
    TextView name;

    @BindView(R.id.custom_value)
    TextView value;

    ViewHolder(View view) {
        super(view);
        ButterKnife.bind(this, view);
        view.setOnClickListener(this);
        if (withContextMenu) {
            view.setOnCreateContextMenuListener(this);
        }
    }

    @Override
    public void onClick(View v) {
        int position = getAdapterPosition();
        if (listener != null) {
            listener.onCustomerSelected(objects.get(position));
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        PopupMenu popup = new PopupMenu(v.getContext(), v);
        popup.getMenuInflater().inflate(R.menu.custom_menu, popup.getMenu());
        popup.setOnMenuItemClickListener(this);
        popup.show();
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        if (listener != null) {
            CustomObject object = objects.get(getAdapterPosition());
            listener.onCustomerMenuAction(object, item);
        }
        return false;
    }
}

public CustomerAdapter(List<CustomObject> objects, OnItemSelectedListener listener, boolean withContextMenu) {
    this.listener = listener;
    this.objects = objects;
    this.withContextMenu = withContextMenu;
}

public interface OnItemSelectedListener {

    void onSelected(CustomObject object);

    void onMenuAction(CustomObject object, MenuItem item);
}

@Override
public CustomerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.snippet_custom_object_line, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
    CustomObject object = objects.get(position);
    holder.name.setText(object.getName());
    holder.value.setText(object.getValue());
}

@Override
public int getItemCount() {
    return objects.size();
}
}

Pełna treść tutaj https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c

Brett Cherrington
źródło
0

Możesz przekazać OnCreateContextMenuListener do ViewHolder podczas wiązania. Ten odbiornik może tworzyć niestandardowe menu dla każdego elementu danych. Po prostu dodaj setOnCreateContextMenuListener w swoim ViewHolder i wywołaj go podczas wiązania.

     public static class ItemViewHolder extends RecyclerView.ViewHolder
     {


        public ItemViewHolder(View itemView) {
            super(itemView);


        }
        void setOnCreateContextMenuListener(View.OnCreateContextMenuListener listener) {
            itemView.setOnCreateContextMenuListener(listener);
        }

}

W adapterze:

      @Override
     public void onBindViewHolder(ItemViewHolder viewHolder,
                    int position) {
         final MyObject myObject = mData.get(position);
         viewHolder.setOnCreateContextMenuListener(new OnCreateContextMenuListener(){

                    @Override
                    public void onCreateContextMenu(ContextMenu menu,
                            View v, ContextMenuInfo menuInfo) {
                        switch (myObject.getMenuVariant() {
                            case MNU_VARIANT_1:
                                menu.add(Menu.NONE, CTX_MNU_1, 
                                        Menu.NONE,R.string.ctx_menu_item_1);    
                                menu.add(Menu.NONE, CTX_MNU_2,Menu.NONE, R.string.ctx_menu_item_2); 
                            break;
                            case MNU_VARIANT_2:
                                menu.add(Menu.NONE, CTX_MNU_3,Menu.NONE, R.string.ctx_menu_item_3); 
                            break;
                            default:
                                menu.add(Menu.NONE, CTX_MNU_4, 
                                        Menu.NONE, R.string.ctx_menu_item_4);   

                        }
                    }

                });
     }
Alexey Usmanov
źródło
0

W moim przypadku musiałem wykorzystać w onContextItemSelected()metodzie dane z mojego fragmentu . Rozwiązaniem, które ostatecznie wybrałem, było przekazanie wystąpienia fragmentu do mojego adaptera i zarejestrowanie elementu widoku w uchwycie widoku:

@Override
public void onBindViewHolder(final MyListAdapter.ViewHolder viewHolder, int position) {
    final Object rowObject = myListItems.get(position);

    // Do your data binding here

    viewHolder.itemView.setTag(position);
    fragment.registerForContextMenu(viewHolder.itemView);
}

Następnie onCreateContextMenu()możesz zapisać indeks do zmiennej lokalnej:

selectedViewIndex = (int)v.getTag();

i odzyskaj w formacie onContextItemSelected()

Eric B.
źródło
0

Gdy pierwszy raz napotkałem ten problem z normalnymi adapterami, utworzyłem własną podklasę widoku niestandardowego i przechowywałem w niej potrzebne rzeczy. Naprawdę nie podobało mi się to rozwiązanie i spędziłem dużo czasu przyglądając się wspaniałym pomysłom, które zaproponowali ludzie, i zdecydowałem, że nie podobają mi się bardziej. Złożyłem więc wszystko razem, potrząsnąłem tym przez chwilę i wyszedłem z czymś nowym, co mi się podoba.

Zaczynamy od kilku klas użytkowych. ContextMenuHandler jest interfejsem dla dowolnego obiektu, który będzie obsługiwał menu kontekstowe. W praktyce będzie to podklasa ViewHolder, ale teoretycznie może to być prawie wszystko

/**
 * Interface for objects that wish to create and handle selections from a context
 * menu associated with a view
 */
public interface ContextMenuHandler extends View.OnCreateContextMenuListener {

  boolean onContextItemSelected(MenuItem item);
}

Dalej jest interfejs, który musi zostać zaimplementowany przez dowolny View, który będzie używany jako bezpośredni element podrzędny RecyclerView.

public interface ViewWithContextMenu {
  public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);

  public ContextMenuHandler getContextMenuHandler();
}

Następnie każdy widok, który ma utworzyć menu kontekstowe jako element podrzędny RecylcerView, musi implementować ViewWIthContextMenu. W moim przypadku potrzebowałem tylko podklasy LinearLayout.

public class LinearLayoutWithContextMenu extends LinearLayout implements ViewWithContextMenu {

  public LinearLayoutWithContextMenu(Context context) {
    super(context);
   }

  public LinearLayoutWithContextMenu(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  private ContextMenuHandler handler;

  @Override
  public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler) {
    this.handler = handler;
    setOnCreateContextMenuListener(fragment);
  }

  @Override
  public ContextMenuHandler getContextMenuHandler() {
    return handler;
  }
}

Na koniec potrzebujemy podrasowanej klasy Fragment, aby przechwycić wywołania menu kontekstowego i przekierować je do odpowiedniego modułu obsługi.

public class FragmentWithContextMenu extends Fragment {

  ContextMenuHandler handler = null;

  @Override
  public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, view, menuInfo);
    handler = null;
    if (view instanceof ViewWithContextMenu) {
      handler = ((ViewWithContextMenu)view).getContextMenuHandler();
      if (handler != null) handler.onCreateContextMenu(menu, view, menuInfo);
    }
  }

  @Override
  public boolean onContextItemSelected(MenuItem item) {
    if (handler != null) {
      if (handler.onContextItemSelected(item)) return true;
    }
    return super.onContextItemSelected(item);
  }
}

Mając to wszystko na swoim miejscu, ostateczna implementacja jest dość prosta. Główny fragment musi mieć podklasę FragmentWithContextMenu. Normalnie konfiguruje główne okno RecylerWindow i przekazuje się do podklasy Adapter. Wygląda jak podklasa Adapter

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {

  private final FragmentWithContextMenu fragment;

  Adapter(FragmentWithContextMenu fragment) {
    this.fragment = fragment;
  }

  @Override
  public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(context)
        .inflate(R.layout.child_view, parent, false);
    return new ViewHolder(view);
  }

  @Override
  public void onBindViewHolder(final Adapter.ViewHolder holder, int position) {
    // Logic needed to bind holder to specific position
    // ......
  }

  @Override
  public int getItemCount() {
    // Logic to return current item count
    // ....
  }

  public class ViewHolder extends RecyclerView.ViewHolder implements ContextMenuHandler {

    ViewHolder(View view) {
      super(view);
      ((ViewWithContextMenu)view).setContextMenuHandler(fragment, this);

      view.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {

          // Do stuff to handle simple clicks on child views
          // .......
        }
      });
    }

   @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {

      // Logic to set up context menu goes here
      // .... 
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {

      // Logic to handle context menu item selections goes here
      // ....

      return true;
    }
  }
}

O to chodzi. Wygląda na to, że wszystko działa. Umieścił wszystkie klasy narzędzi w osobnym pakiecie contextmenu, więc mogłem podać nazwy klas, które pasują do klas, które są podklasy, ale pomyślałem, że byłoby to bardziej zagmatwane.

kencorbin
źródło
-1

Ok, na podstawie odpowiedzi @ Flexo złożę mPosition do zamówienia ...

protected class ExampleViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {

    int mPosition;

    public KWViewHolder(View itemView) {
        super(itemView);
        itemView.setOnCreateContextMenuListener(this);
    }

    public void setPosition(int position) {
        mPosition = position;
    }

    @Override
    public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
        contextMenu.setHeaderTitle(R.string.menu_title_context);
        contextMenu.add(0, R.id.menu_delete, mPosition, R.string.delete);
    }
}

następnie w onContextItemSelected używam

item.getOrder() 

I wszystko działa dobrze, łatwo otrzymuję pozycję tablicy

windX
źródło