So erstellen Sie ein Kontextmenü für RecyclerView

96

Wie implementiere ich ein Kontextmenü für RecyclerView?Anscheinend registerForContextMenu(recyclerView)funktioniert das Aufrufen nicht. Ich nenne es aus einem Fragment. Hat jemand Erfolg damit gehabt?

Binoy Babu
quelle
Ich bin im selben Boot. Versuchte verschiedene ListView-Ansätze mit AdapterContextMenuInfo - kann aber die info.position nicht erhalten
RoundSparrow hilltx
Ich denke, die Tage des Kontextmenüs sind vorbei.
Binoy Babu
4
Hey - ich habe es zum Laufen gebracht;) Referenz: stackoverflow.com/questions/2321332/… - der ViewHolder ist für mich der onClick-Listener - ich habe ihn auch zum OnCreateContextMenuListener gemacht. Der Schlüssel zu all dem ist, dass mir klar wurde, dass immer nur EIN Menü geöffnet sein kann. Der Adapter benötigt also nur ein Int, um zu erfahren, welches das letzte RecyclerView-Listenelement war, auf das das Menü geklickt hat ... dann kann das Fragment / die Aktivität Fragen Sie den Adapter, wenn der tatsächliche Menüpunkt angeklickt wird.
RoundSparrow Hilltx

Antworten:

92

Sie können nicht direkt diese Methode wie implementieren OnClickListener , OnContextMenuListener usw. weil RecycleView erstreckt android.view.ViewGroup . Wir können diese Methode also nicht direkt anwenden. Wir können diese Methoden in der ViewHolder- Adapterklasse implementieren . Wir können das Kontextmenü in RecycleView folgendermaßen verwenden:

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


    }

Jetzt gehen wir genauso vor, während wir das Kontextmenü implementieren.

@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"); 

}

Wenn Sie Schwierigkeiten haben, fragen Sie im Kommentar.

Prabhakar
quelle
7
Ok, und dann implementieren wir eine onContextItemSelectedAktivität / Fragmentebene. getTitlefunktioniert, getItemIdfunktioniert, getMenuInfoliefert aber null. Also, wie bekommt man das in den Griff ViewHolder?
Michael Schmidt
@MichaelSchmidt Kannst du mir deinen Code zeigen, wo du Kontextmenü-Informationen implementierst?
Prabhakar
7
Nachdem ich ein bisschen experimentiert habe, kann ich das auch nicht zum Laufen bringen, getMenuInfo()gibt null in zurück onContextItemSelected(). Vielleicht haben die Leute, die es zum Laufen gebracht haben, eine onCreateContextMenu()Methode im Blick weiter oben in der Hierarchie (das RecyclerViewoder Fragment)? Das kann funktionieren, bringt uns dann aber zu anderen Antworten auf diese Frage.
NeilS
3
Prabhakbar Sie haben nicht erwähnt, wie Sie das angeklickte Element oder die Ansicht erhalten?
Benjamin Stürmer
6
Sie können verwenden menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");und dann in Ihrer item.getGroupId()
Rückrufmethode
98

Danke für die Infos und Kommentare. Ich konnte ContextMenufür Artikel in erreichen Recyclerview.

Hier ist was ich getan habe

in der onViewCreatedMethode von Fragment oder der onCreateMethode von Activity :

registerForContextMenu(mRecyclerView);

Dann im Adapter hinzufügen

private int position;

public int getPosition() {
    return position;
}

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

Lassen Sie die ViewHolderKlasse implementierenOnCreateContextMenuListener

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

onBindViewHolderMethode Add OnLongClickListeneron the Holder.itemView, um die Position zu erfassen, bevor das Kontextmenü geladen wird:

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

Dann onViewRecycledentfernen Sie den Hörer so , dass es keine Referenzfragen. (möglicherweise nicht erforderlich).

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

Schließlich überschreiben Sie im Fragment / Aktivität das onContextItemSelectedwie unter:

@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
quelle
1
position = ((BackupRestoreListAdapter) getAdapter ()). getPosition (); -> get error: Die Methode getAdapter () ist undefiniert für den Typ ..., können Sie getAdapter Methode zeigen
nguoixanh
1
Toller Vorschlag, danke. Klein: viewHolder.getPosition () ist veraltet. Was raten Sie zur Verbesserung?
tm1701
10
Verwenden Sie viewHolder.getAdapterPosition () anstelle von getPosition ()
Sagar Chavada
2
Für diejenigen, die den Fehler getAdapter () erhalten, habe ich ihn behoben, indem ich einen Verweis auf meine RecyclerView gespeichert und ihn dann wie folgt verwendet habe: ((BackupRestoreListAdapter) recyclerView.getAdapter ()). GetPosition ();
Kevin Amorim
1
Und wo genau ist R.id.ctx_menu_remove_backup?
Akubi
29

Die aktuelle Antwort ist nicht korrekt. Hier ist eine funktionierende Implementierung:

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

In Ihrem Fragment (oder Ihrer Aktivität):

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

Und schließlich in Ihrem ViewHolder:

class MyViewHolder extends RecyclerView.View.ViewHolder {
    ...
    private void onLongClick() {
        itemView.showContextMenu();
    }
}
Renaud Cerrato
quelle
Fügen Sie den RecyclerView-Konstruktor hinzu, den Sie in Ihrem ContextMenuRecyclerView implementieren mussten. Und auch getChildPosition()ist jetzt veraltet. Ich habe getChildAdapterPosition()stattdessen verwendet.
Juan José Melero Gómez
1
Hinweis: Entschuldigung, ich habe vergessen hinzuzufügen: getChildPosition()ist veraltet in com.android.support:recyclerview-v7:22.0.0.
Juan José Melero Gómez
1
das funktioniert nicht. Sie können nicht auf getView (). showContextMenu () von RecyclerView.View.ViewHolder zugreifen.
Mulgard
4
Das funktioniert bei mir. Es ist jedoch nicht erforderlich, dass onLongClick () in MyViewHolder vorhanden ist. Es reicht aus, itemView.setLongClickable (true) im Konstruktor festzulegen. Das Kontextmenü wird angezeigt, wenn OnLongClickListener nicht registriert ist.
Erlen
2
Wichtig auch: Vergessen Sie beim Erweitern der RecyclerView auf ContextMenuRecyclerView nicht, die von IDE vorgeschlagenen CONSTRUCTORS hinzuzufügen. Insbesondere wenn Sie den Konstruktor mit zwei Argumenten, der Context und AttributeSet verwendet, nicht implementieren, kann Android Ihr Layout-XML nicht aufblasen.
Lidkxx
24

Versuchen Sie dies für ein ViewElement in 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;
                }
            });
        }
    });

Sie können es verwenden, um Daten für ein ViewHolderElement festzulegen

Sergey Bondarenko
quelle
Genau das, was ich für das Kontextmenü in einer
Bildansicht
2
Für alle, die sich das jetzt ansehen, funktioniert dies nur mit API 23 und höher.
SWoo
16

Die Antwort von Prabhakar ist korrekt, aber er hat nicht erklärt, wie man Daten in Bezug auf das gedrückte Element erhält, wenn ein Kontextmenüelement ausgewählt wird. Wir können einen onContextItemSelectedRückruf verwenden, sind jedoch in diesem Fall ContextMenuInfonicht verfügbar ( null) (wenn die getContextMenuInfo()Methode für eine gedrückte Ansicht nicht überschrieben wird). Die einfachste Lösung besteht also darin, OnMenuItemClickListenerdirekt zum hinzuzufügen 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
quelle
1
Erklären Sie klar, was Ihr Code-Snippet macht und wie. Nur ein kopierter Code reicht nicht aus, auch wenn er sich lohnt.
Peterh - Wiedereinsetzung Monica
Dies scheint ein vernünftiger Kompromiss zu sein, wenn Sie keine benutzerdefinierten Unterklassen erstellen möchten, die RecyclerViewnur zum Überschreiben getContextMenuInfousw. dienen sollen, auch wenn dies nicht ganz so effizient ist, wie das Fragment / die Aktivität Klicks verarbeiten zu lassen. Die Zuhörer haben Zugriff auf die Daten im Halter, sodass Sie keine Position benötigen sollten. Und theoretisch könnten Sie die Position beim Binden in Ihrem Adapter trotzdem zwischenspeichern und die Delegierung verwenden, um aus Ihrem Halter herauszurufen, wenn Sie müssen, obwohl die Verwendung der Contextaus einer der gebundenen Ansichten manchmal ausreichend sein kann.
Qix
10

@ Renauds Antwort funktionierte für mich, erforderte jedoch zuerst einige Code-Korrekturen. Es ist, als hätte er Ausschnitte aus verschiedenen Iterationen seines Codes gepostet. Die Änderungen, die vorgenommen werden müssen, sind:

  • RecyclerContextMenuInfound RecyclerViewContextMenuInfosind die gleiche Klasse. Wähle einen Namen und bleibe dabei.
  • Das ViewHoldermuss implementiert werden View.OnLongClickListener, und denken Sie daran, setOnLongClickListener()das Element im Konstruktor aufzurufen .
  • Im onLongClick()Hörer getView().showContextMenu()ist das völlig falsch. Sie müssen showContextMenuForChild()Ihre anrufen ContextMenuRecyclerView, sonst werden ContextMenuInfoSie einsteigen onCreateContextMenu()und onContextItemSelected()werden null sein.

Mein bearbeiteter Code unten:

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

In Ihrem Fragment:

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

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

Also, stellen Sie sicher , dass Sie ersetzen RecyclerViewmit ContextMenuRecyclerViewim Layout!

josh2112
quelle
1
Thanks @ josh2112 für den Hinweis mich Tippfehler, ich sie nur korrigiert - ABER in Bezug auf Ihren letzten Punkt, können Sie ersetzen recyclerView.showContextMenuForChild(itemView);durch itemView.showContextMenu().
Renaud Cerrato
1
Wichtig auch: Vergessen Sie beim Erweitern der RecyclerView auf ContextMenuRecyclerView nicht, die von IDE vorgeschlagenen CONSTRUCTORS hinzuzufügen. Insbesondere wenn Sie den Konstruktor mit zwei Argumenten, der Context und AttributeSet verwendet, nicht implementieren, kann Android Ihr Layout-XML nicht aufblasen.
Lidkxx
5

Hier ist eine saubere Möglichkeit, den Menükontext für RecyclerView-Elemente zu verwenden

Zunächst benötigen Sie eine Artikelposition

In der Adapterklasse:

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

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

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

In onBindViewHolderHook der benutzerdefinierte 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;
            }
        });

Erstellen Sie in MainActivity (Aktivität / Fragment) ein Feld:

private int mCurrentItemPosition;

Legen Sie in Ihrem Adapterobjekt den benutzerdefinierten Listener fest:

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

Jetzt haben Sie eine leckere Position für jeden Gegenstand, auf den Sie lange geklickt haben 😋

Zweitens erstellen Sie Ihr Menü

In res -> menu Erstellen Sie eine Datei mit Ihrem Menüpunkt 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>

In MainActivity: Implementieren Sie beide onCreateContextMenuund 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;
}

Drittens zurück zu Ihrem Adapterobjekt

  1. Registrieren Sie Ihr Kontextmenü.
  2. Zeigen Sie das Kontextmenü an.

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

Hoffe ich vergesse nichts 🤔

Weitere Infos unter Menüdokumentation

MohammadL
quelle
Vielen Dank! Wie übergebe ich Daten an das Kontextmenü? Zum Beispiel Artikel-ID, Artikeltext und so weiter.
CoolMind
4

Hier ist eine einfachere Möglichkeit, dies mit Kotlin zu tun, die für mich funktioniert hat. Die größte Herausforderung besteht darin, die Position des Gegenstandes herauszufinden, der gedrückt wurde. In Ihrem Adapter können Sie dieses Code-Snippet platzieren und es kann die Position des Elements erfassen, für das das Kontextmenü angezeigt wird. das ist alles.

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

} 
Mickey Maus
quelle
2
Dies ist die natürlichste und kontrollierbarste Art, dies zu tun
Nima
3

Ich habe meine Lösung mit der Lösung von @Hardik Shah kombiniert:

In der Aktivität habe ich:

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

Im Adapter habe ich:

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

In Fragment habe ich:

@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);
    }
}
Array
quelle
2

Ich bin vielleicht zu spät zur Party, aber ich habe eine funktionierende Lösung . Ich habe einen Kern dafür gemacht.

Kontextmenü zu RecyclerView hinzufügen

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
quelle
1

Hallo Leute, es ist eine Alternative herausgekommen, die für mich funktioniert. Ich registriere einfach meine itemView bei registerContextMenu im ViewHolder-Konstruktor und setze auch einen onLongClikcListener auf dieselbe Ansicht. In der Implementierung von onLongClick (View v) erhalte ich einfach die angeklickte Position mit getLayoutPosition () und speichere sie in einer Instanzvariablen (ich habe eine Klasse erstellt, um diese Daten darzustellen, genau wie ContextMenuInfo funktionieren soll), aber wichtiger ist es, dies zu tun Stellen Sie sicher, dass Sie bei dieser Methode false zurückgeben . Jetzt müssen Sie nur noch onContextItemSelected (MenuItem-Element) in sich aufnehmen, die Daten lesen, die Sie in Ihrer Instanzvariablen speichern, und wenn sie gültig sind, fahren Sie mit Ihren Aktionen fort. Hier ist es ein Ausschnitt.

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

Ich mache ViewHolder implementiert OnLongClickListener, aber Sie können es auf jede Weise tun, die Sie bevorzugen.

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

Sie können dies auch im Adapter oder in einer anderen Ansicht im ViewHolder (dh einer Textansicht) festlegen. Wichtig ist die Implementierung von 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);
}

Das Beste daran ist, dass Sie das LongClick-Ereignis, das in den gewünschten Fällen true zurückgibt, weiterhin verarbeiten können und das conextMenu nicht angezeigt wird.

Diese Methode funktioniert, weil registerForContextView die Ansicht LongClickable macht und wenn es Zeit ist, das ContextMenu zu verarbeiten, ruft das System performLongClick auf, das zuerst eine onLongClick-Implementierung aufruft, und wenn es false zurückgibt, ruft es showContextMenu auf.

Raziel25
quelle
1

Ich benutze diese Lösung seit einiger Zeit und habe ziemlich gut für mich funktioniert.

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

Implementieren Sie nun in Ihrem Fragment oder Ihrer Aktivität die folgenden Methoden.

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

Registrieren Sie sich schließlich für das Kontextmenü in der Recycling-Ansicht

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

Das sollte funktionieren!

Rakesh Gopathi
quelle
1

So können Sie das Kontextmenü für RecyclerView implementieren und die Position des Elements abrufen, für das das Kontextmenüelement ausgewählt wurde:

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
quelle
1

Eine Lösung für diejenigen, die beim Anruf die Artikel-ID erhalten möchten ContextMenu.

Wenn Sie eine RecyclerViewmit Elementen wie diesen haben (mit anklickbaren ImageView):

aufführen

dann sollten Sie Rückrufe von erhalten 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()
    }
}

Warnung!

Wenn Sie ein ViewPagerFragment verwenden, das auf einem Fragment basiert (alle Seiten sind ähnliche Listen), tritt ein Problem auf. Wenn Sie überschreiben, um onContextItemSelectedzu verstehen, welcher Menüpunkt ausgewählt wurde, erhalten Sie auf der ersten Seite eine Listenelement-ID! Um dieses Problem zu beheben, lesen Sie Falsches Fragment in ViewPager empfängt den Aufruf onContextItemSelected .

CoolMind
quelle
0

Ich habe Probleme damit, weil Android dies in RecyclerView, das für ListView sehr gut funktioniert hat, für mich nicht gut handhabt.

Das schwierigste Teil ist, dass das ContextMenuInfo-Teil in eine Ansicht eingebettet ist, die Sie nur durch Überschreiben der Ansicht anhängen können.

Sie benötigen also einen Wrapper, mit dem Sie die Positionsinformationen an die Aktivität senden können.

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

}}

Wenn Sie dann in Ihrem RecyclerAdapter ViewHolders erstellen, müssen Sie den Wrapper als Stammansicht festlegen und in jeder Ansicht das Kontextmenü registrieren.

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

}}

Und schließlich können Sie in Ihrer Aktivität das tun, was Sie normalerweise tun:

@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
quelle
0

Am besten verwenden Sie das Kontextmenü mit der Recycler-Ansicht, wenn Sie eine benutzerdefinierte Recycler-Ansicht erstellen, die getContextMenuInfo()Methode überschreiben und Ihre eigene Instanz des Kontextmenü-Infoobjekts zurückgeben, damit Sie Positionen abrufen können, wenn es erstellt wurde und wenn auf das Menü geklickt wird:

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

Schauen Sie sich diesen Kern an, den ich erstellt habe:

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

ReeSen
quelle
0

Wenn Sie vermeiden möchten, das Menü in Ihrem Code im Adapter / ViewHolder manuell zu definieren, können Sie ein Popup-Menü verwenden und die Menüoptionen aus einer Standardressourcendatei menu.xml aufblasen.

Das folgende Beispiel zeigt dies, einschließlich der Möglichkeit, einen Listener zu übergeben, den Sie in Ihrem Fragment / Ihrer Aktivität implementieren können, um auf Kontextmenüklicks zu reagieren.

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

Vollständiger Überblick hier https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c

Brett Cherrington
quelle
0

Sie können OnCreateContextMenuListener beim Binden an ViewHolder übergeben. Dieser Listener kann für jedes Datenelement ein benutzerdefiniertes Menü erstellen. Fügen Sie einfach setOnCreateContextMenuListener in Ihren ViewHolder ein und rufen Sie es während der Bindung auf.

     public static class ItemViewHolder extends RecyclerView.ViewHolder
     {


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


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

}}

Im Adapter:

      @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
quelle
0

In meinem Fall musste ich Daten aus meinem Fragment in der onContextItemSelected()Methode verwenden. Die Lösung bestand darin, eine Instanz des Fragments an meinen Adapter zu übergeben und das Ansichtselement im Ansichtshalter zu registrieren:

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

Dann onCreateContextMenu()können Sie den Index in einer lokalen Variablen speichern:

selectedViewIndex = (int)v.getTag();

und abrufen in onContextItemSelected()

Eric B.
quelle
0

Als ich zum ersten Mal mit normalen Adaptern auf dieses Problem stieß, erstellte ich meine eigene benutzerdefinierte Ansichtsunterklasse und speicherte das benötigte Material darin. Ich mochte diese Lösung wirklich nicht und verbrachte viel Zeit damit, mir die großartigen Ideen anzusehen, die die Leute vorgeschlagen haben, und entschied, dass ich sie nicht besser mochte. Also habe ich alles zusammengefügt, eine Weile herumgeschüttelt und etwas Neues herausgebracht, das mir gefällt.

Wir beginnen mit ein paar Utility-Klassen. ContextMenuHandler ist eine Schnittstelle für jedes Objekt, das das Kontextmenü verarbeiten soll. In der Praxis wird dies eine ViewHolder-Unterklasse sein, aber theoretisch könnte es fast alles sein

/**
 * 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);
}

Als nächstes folgt eine Schnittstelle, die von jeder Ansicht implementiert werden muss, die als unmittelbares untergeordnetes Element einer RecyclerView verwendet werden soll.

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

  public ContextMenuHandler getContextMenuHandler();
}

Als Nächstes muss jede Ansicht, die als untergeordnetes Element einer RecylcerView ein Kontextmenü erstellen soll, ViewWIthContextMenu implementieren. In meinem Fall brauchte ich nur eine Unterklasse von 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;
  }
}

Und schließlich benötigen wir eine aufgemotzte Fragment-Klasse, um die Kontextmenü-Aufrufe abzufangen und an den entsprechenden Handler umzuleiten.

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

Mit all dem ist die endgültige Implementierung ziemlich einfach. Das Hauptfragment muss FragmentWithContextMenu unterordnen. Es richtet das Haupt-RecylerWindow normal ein und übergibt sich selbst an die Adapter-Unterklasse. Die Adapter-Unterklasse sieht aus wie

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

Das ist alles. Es scheint alles zu funktionieren. Alle Utility-Klassen wurden in ein separates Kontextmenü-Paket gestellt, sodass ich die Klassennamen hätte angeben können, die mit den dortigen Klassen übereinstimmen, aber ich dachte, das wäre verwirrender.

Kencorbin
quelle
-1

Ok, basierend auf der Antwort von @ Flexo werde ich mPosition bestellen ...

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

dann verwende ich in onContextItemSelected

item.getOrder() 

Und alles funktioniert gut Ich bekomme leicht die Position des Arrays

windX
quelle