Comment créer un menu contextuel pour RecyclerView

97

Comment implémenter le menu contextuel pour RecyclerView?Apparemment appeler registerForContextMenu(recyclerView)ne fonctionne pas. Je l'appelle à partir d'un fragment. Quelqu'un a-t-il réussi à mettre en œuvre cela?

Binoy Babu
la source
Je suis dans le meme bateau. J'ai essayé diverses approches ListView avec AdapterContextMenuInfo - mais je ne peux pas obtenir l'info.position
RoundSparrow hilltx
Je pense que les jours de menu contextuel sont terminés.
Binoy Babu
4
Hey - je l'ai fait fonctionner;) refeerence: stackoverflow.com/questions/2321332/… - le ViewHolder pour moi est l'écouteur onClick - Je l'ai également fait le OnCreateContextMenuListener. La clé de tout cela est que j'ai réalisé qu'un seul menu peut être ouvert à la fois - donc l'adaptateur a juste besoin d'un int pour savoir quel était le dernier élément de la liste RecyclerView sur lequel le menu avait été cliqué ... alors le fragment / activité peut demandez à l'adaptateur lorsqu'il obtient le clic réel sur l'élément de menu.
RoundSparrow hilltx

Réponses:

92

Vous ne pouvez pas implémenter directement ces méthodes comme onClickListener , OnContextMenuListener etc. car RecycleView étend android.view.ViewGroup . Nous ne pouvons donc pas utiliser directement ces méthodes. Nous pouvons implémenter ces méthodes dans la classe d'adaptateur ViewHolder . Nous pouvons utiliser le menu contextuel dans RecycleView comme ceci:

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


    }

Maintenant, nous suivons la même procédure tout en implémentant le menu contextuel.

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

}

Si vous rencontrez des difficultés, demandez en commentaire.

Prabhakar
la source
7
Ok, puis nous implémentons un niveau onContextItemSelectedd'activité / fragment. getTitlefonctionne, getItemIdfonctionne, mais getMenuInfodélivre null. Alors, comment obtenir le ViewHolder?
Michael Schmidt
@MichaelSchmidt peut me montrer votre code où vous implémentez les informations du menu contextuel.
Prabhakar
7
Après avoir expérimenté un peu, je ne peux pas faire fonctionner cela non plus, getMenuInfo()renvoie null dans onContextItemSelected(). Peut-être que les gens qui l'ont fait fonctionner ont eu une onCreateContextMenu()méthode dans une vue plus haut dans la hiérarchie (le RecyclerViewou Fragment)? Cela peut fonctionner mais nous amène ensuite à d'autres réponses à cette question.
NeilS
3
Prabhakbar vous n'avez pas mentionné comment obtenir l'élément cliqué ni la vue?
Benjamin Stürmer
6
Vous pouvez utiliser menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");puis dans votre test de méthode de rappel pour item.getGroupId()obtenir la position
JacobPariseau
99

Merci pour les informations et les commentaires. J'ai pu réaliser ContextMenudes objets en Recyclerview.

Voici ce que j'ai fait

dans la onViewCreatedméthode Fragment ou la méthode Activity onCreate:

registerForContextMenu(mRecyclerView);

Puis dans l'adaptateur, ajoutez

private int position;

public int getPosition() {
    return position;
}

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

faire ViewHolderimplémenter la classeOnCreateContextMenuListener

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

onBindViewHolderadd OnLongClickListeneron the holder.itemView pour capturer la position avant le chargement du menu contextuel:

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

Ensuite, onViewRecycledsupprimez l'écouteur afin qu'il n'y ait aucun problème de référence. (peut ne pas être requis).

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

Enfin, dans le fragment / activité, remplacez onContextItemSelectedcomme ci-dessous:

@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
la source
1
position = ((BackupRestoreListAdapter) getAdapter ()). getPosition (); -> get error: La méthode getAdapter () n'est pas définie pour le type ..., pouvez-vous afficher la méthode
getAdapter
1
Excellente suggestion, merci. Mineur: le viewHolder.getPosition () est obsolète. Quels sont vos conseils d'amélioration?
tm1701
10
utilisez viewHolder.getAdapterPosition () au lieu de getPosition ()
Sagar Chavada
2
Pour ceux qui obtiennent l'erreur getAdapter (), je l'ai résolu en enregistrant une référence à mon RecyclerView puis en l'utilisant comme: ((BackupRestoreListAdapter) recyclerView.getAdapter ()). GetPosition ();
Kevin Amorim
1
Et où est exactement R.id.ctx_menu_remove_backup?
akubi
29

La réponse actuelle n'est pas correcte. Voici une implémentation fonctionnelle:

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

Dans votre fragment (ou activité):

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

Et enfin, dans votre ViewHolder:

class MyViewHolder extends RecyclerView.View.ViewHolder {
    ...
    private void onLongClick() {
        itemView.showContextMenu();
    }
}
Renaud Cerrato
la source
Veuillez ajouter le constructeur RecyclerView que vous avez dû implémenter sur votre ContextMenuRecyclerView. Et aussi, getChildPosition()est obsolète maintenant. J'ai utilisé à la getChildAdapterPosition()place.
Juan José Melero Gómez
1
Remarque: Désolé, j'ai oublié d'ajouter: getChildPosition()est obsolète dans com.android.support:recyclerview-v7:22.0.0.
Juan José Melero Gómez
1
cela ne fonctionne pas. vous ne pouvez pas accéder à getView (). showContextMenu () à partir de RecyclerView.View.ViewHolder.
Mulgard
4
Cela fonctionne pour moi. Mais il n'est pas nécessaire d'avoir onLongClick () dans MyViewHolder, il suffit de définir itemView.setLongClickable (true) dans le constructeur, le menu contextuel apparaîtra lorsque OnLongClickListener n'est pas inscrit.
aulnes
2
Important également: lors de l'extension de RecyclerView à ContextMenuRecyclerView, n'oubliez pas d'AJOUTER LES CONSTRUCTEURS suggérés par l'IDE. Plus précisément, si vous n'implémentez pas le constructeur à deux arguments qui prend Context et AttributeSet, Android ne pourra pas gonfler votre mise en page XML.
lidkxx
24

Essayez ceci pour un Viewélément dans 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;
                }
            });
        }
    });

Vous pouvez l'utiliser pour définir des données sur un ViewHolderélément

Sergey Bondarenko
la source
Exactement ce dont j'avais besoin pour le menu contextuel sur une vue d'image dans une vue recyclée
Themos
2
Pour quiconque regarde cela maintenant, cela ne fonctionne que sur l'API 23 et plus.
SWoo
16

La réponse de Prabhakar est correcte, mais il n'a pas expliqué comment obtenir une donnée, liée à l'élément pressé, lorsqu'un élément du menu contextuel est sélectionné. Nous pouvons utiliser le onContextItemSelectedrappel, mais ContextMenuInfon'est pas disponible ( null) dans ce cas (si la getContextMenuInfo()méthode n'est pas remplacée pour une vue pressée). Ainsi, la solution la plus simple consiste à ajouter OnMenuItemClickListenerdirectement au fichier 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
la source
1
Expliquez clairement ce que fait votre extrait de code et comment. Seul un code copié ne suffit pas, même s'il en vaut la peine.
peterh
Cela semble être un compromis raisonnable si vous ne voulez pas créer des sous-classes personnalisées de RecyclerViewjuste pour remplacer, getContextMenuInfoetc., même si ce n'est pas aussi efficace que de laisser le fragment / l'activité gérer les clics. Les auditeurs auront accès aux données dans le support, vous ne devriez donc pas avoir besoin de position. Et théoriquement, vous pouvez de toute façon mettre en cache la position lors de la liaison dans votre adaptateur et utiliser la délégation pour appeler votre titulaire si vous le devez, bien que l'utilisation de l' Contextune des vues liées puisse parfois suffire.
qix
10

La réponse de @ Renaud a fonctionné pour moi mais a d'abord nécessité plusieurs corrections de code. C'est comme s'il avait publié des extraits de plusieurs itérations différentes de son code. Les modifications à apporter sont:

  • RecyclerContextMenuInfoet RecyclerViewContextMenuInfosont de la même classe. Choisissez un nom et respectez-le.
  • Le ViewHolderdoit implémenter View.OnLongClickListeneret n'oubliez pas d'appeler setOnLongClickListener()l'élément dans le constructeur.
  • Dans l' onLongClick()auditeur, getView().showContextMenu()est complètement faux. Vous devez appeler showContextMenuForChild()votre ContextMenuRecyclerView, sinon ContextMenuInfovous entrez onCreateContextMenu()et onContextItemSelected()sera nul.

Mon code modifié ci-dessous:

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

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

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

Assurez-vous également de remplacer RecyclerViewpar ContextMenuRecyclerViewdans votre mise en page!

josh2112
la source
1
Merci @ josh2112 de m'avoir signalé des fautes de frappe, je viens de les corriger - MAIS concernant votre dernier point, vous pouvez le remplacer recyclerView.showContextMenuForChild(itemView);par itemView.showContextMenu().
Renaud Cerrato
1
Important également: lors de l'extension de RecyclerView à ContextMenuRecyclerView, n'oubliez pas d'AJOUTER LES CONSTRUCTEURS suggérés par l'IDE. Plus précisément, si vous n'implémentez pas le constructeur à deux arguments qui prend Context et AttributeSet, Android ne pourra pas gonfler votre mise en page XML.
lidkxx
5

Voici une manière propre d'utiliser le contexte de menu sur les éléments RecyclerView

Tout d'abord, vous avez besoin d'une position d'article

Dans la classe Adapter:

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

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

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

En onBindViewHoldercrochet l'auditeur personnalisé:

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

Dans MainActivity (Activity / Fragment), créez un champ:

private int mCurrentItemPosition;

Dans votre objet Adapter, définissez l'écouteur personnalisé:

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

Vous avez maintenant une position délicieuse pour tout élément sur lequel vous avez longtemps cliqué 😋

Deuxièmement, créez votre menu

Dans res -> menu Créer un fichier contenant votre élément de 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>

Dans MainActivity: implémentez à la fois onCreateContextMenuet 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;
}

Troisièmement, revenons à votre objet Adapter

  1. Enregistrez votre menu contextuel.
  2. afficher le menu contextuel.

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

J'espère que je n'oublie rien 🤔

Plus d'informations sur la documentation des menus

MohammadL
la source
Merci! Comment passer des données au menu contextuel? Par exemple, l'identifiant de l'élément, le texte de l'élément, etc.
CoolMind
4

Voici un moyen plus simple de le faire avec Kotlin qui a fonctionné pour moi. Le défi majeur est de déterminer la position de l'élément qui a été pressé. À l'intérieur de votre adaptateur, vous pouvez placer cet extrait de code et il pourra capturer la position de l'élément pour lequel le menu contextuel est affiché; c'est tout.

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 la souris
la source
2
C'est la façon la plus naturelle et la plus contrôlable de le faire
nima
3

J'ai combiné ma solution avec la solution de @Hardik Shah:

Dans l'activité j'ai:

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

Dans l'adaptateur, j'ai:

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

En fragment, j'ai:

@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);
    }
}
Tableau
la source
2

Je suis peut-être en retard à la fête mais j'ai une solution de travail . J'en ai fait l'essentiel.

Ajouter un menu contextuel à 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
la source
1

Bonjour les gars, a sorti une alternative qui fonctionne pour moi. Je viens d'enregistrer mon itemView avec registerContextMenu et le constructeur ViewHolder, définissez également un onLongClikcListener sur la même vue. Dans l'implémentation onLongClick (View v), j'obtiens simplement la position cliquée avec getLayoutPosition () et l'enregistre dans une variable d'instance (j'ai créé une classe pour représenter ces données, tout comme ContextMenuInfo devrait fonctionner), mais le plus important est de faire assurez-vous de retourner false dans cette méthode. Tout ce que vous avez à faire maintenant est en vous sur onContextItemSelected (élément MenuItem), lisez les données que vous stockez dans votre variable d'instance et si elles sont valides, poursuivez vos actions. Ici, c'est un extrait.

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

Je fais que ViewHolder implémente OnLongClickListener, mais vous pouvez le faire de la manière que vous préférez.

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

Vous pouvez également le définir dans l'adaptateur ou dans une autre vue que vous avez dans le ViewHolder (c'est-à-dire un TextView). L'important est l'implémentation 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);
}

La meilleure partie est que vous pouvez toujours traiter l'événement LongClick en retournant true dans les cas que vous souhaitez, et le conextMenu n'apparaîtra pas.

Cette méthode fonctionne car registerForContextView rend la vue LongClickable, et lorsqu'il est temps de traiter le ContextMenu, le système appelle performLongClick, qui appelle d'abord une implémentation onLongClick, et si elle retourne false, il appelle ensuite showContextMenu.

Raziel25
la source
1

J'utilise cette solution depuis un certain temps maintenant et cela a très bien fonctionné pour moi.

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

Maintenant, dans votre fragment ou activité, implémentez les méthodes suivantes.

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

Enfin, inscrivez-vous au contexteMenu sur la vue de recyclage

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

Cela devrait fonctionner!

Rakesh Gopathi
la source
1

Voici comment vous pouvez implémenter le menu contextuel pour RecyclerView et obtenir la position de l'élément, pour lequel l'élément de menu contextuel a été sélectionné:

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
la source
1

Une solution pour ceux qui veulent obtenir l'identifiant de l'article lors de l'appelContextMenu .

Si vous avez un RecyclerViewavec des éléments comme celui-ci (contenant cliquable ImageView):

liste

alors vous devriez recevoir des rappels de onClickListener .

Adaptateur

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

Avertissement!

Si vous utilisez un ViewPagerbasé sur un fragment (toutes les pages sont des listes similaires), vous rencontrerez un problème. Lorsque vous remplacez onContextItemSelectedpour comprendre quel élément de menu a été sélectionné, vous obtiendrez un identifiant d'élément de liste à partir de la première page! Pour surmonter ce problème, voir Un fragment incorrect dans ViewPager reçoit un appel onContextItemSelected .

CoolMind
la source
0

J'ai eu du mal à cela car Android ne gère pas cela bien pour moi dans RecyclerView, qui fonctionnait très bien pour ListView.

L'élément le plus difficile est que l'élément ContextMenuInfo est incorporé dans une vue, que vous ne pouvez pas facilement attacher autrement qu'en remplaçant la vue.

Vous aurez donc besoin d'un wrapper qui vous aidera à fournir les informations de position à l'activité.

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

}

Ensuite, dans votre RecyclerAdapter, lorsque vous créez ViewHolders, vous devez définir le Wrapper comme vue racine et enregistrer contextMenu sur chaque vue.

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

}

Et enfin, dans votre activité, vous serez en mesure de faire ce que vous faites habituellement:

@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
la source
0

Le mieux était d'utiliser le menu contextuel avec la vue recycleur si vous créez une vue recycleur personnalisée et remplacez la getContextMenuInfo()méthode et renvoyez votre propre instance de l'objet d'informations du menu contextuel afin que vous puissiez récupérer des positions lors de sa création et lorsque vous cliquez sur le menu:

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

Jetez un œil à l'essentiel que j'ai créé:

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

ReeSen
la source
0

En développant un peu certaines des réponses ci-dessus, si vous souhaitez éviter de définir manuellement le menu dans votre code dans Adapter / ViewHolder, vous pouvez utiliser un PopupMenu et gonfler les options de menu à partir d'un fichier de ressources menu.xml standard.

L'exemple ci-dessous montre cela, y compris la possibilité de transmettre un écouteur que vous pouvez implémenter dans votre fragment / activité pour répondre aux clics du menu contextuel.

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

L'essentiel ici https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c

Brett Cherrington
la source
0

Vous pouvez passer OnCreateContextMenuListener dans ViewHolder lors de la liaison. Cet écouteur peut créer un menu personnalisé pour chaque élément de données. Ajoutez simplement setOnCreateContextMenuListener dans votre ViewHolder et appelez-le pendant la liaison.

     public static class ItemViewHolder extends RecyclerView.ViewHolder
     {


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


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

}

Dans l'adaptateur:

      @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
la source
0

Dans mon cas, j'ai dû utiliser les données de mon fragment dans la onContextItemSelected()méthode. La solution avec laquelle j'ai fini par utiliser était de passer une instance du fragment dans mon adaptateur et d'enregistrer l'élément de vue dans le support de vue:

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

Ensuite, onCreateContextMenu()vous pouvez enregistrer l'index dans une variable locale:

selectedViewIndex = (int)v.getTag();

et récupérez-le dans onContextItemSelected()

Éric B.
la source
0

La première fois que j'ai rencontré ce problème avec des adaptateurs normaux, j'ai fini par créer ma propre sous-classe View personnalisée et y stocker les éléments dont j'avais besoin. Je n'aimais vraiment pas cette solution et j'ai passé beaucoup de temps à regarder les bonnes idées que les gens avaient proposées, et j'ai décidé que je ne les aimais pas mieux. Alors j'ai en quelque sorte tout mis ensemble, je l'ai secoué pendant un moment et je suis sorti avec quelque chose de nouveau que j'aime.

Nous commençons avec quelques classes d'utilité. ContextMenuHandler est une interface pour n'importe quel objet qui va gérer le menu contextuel. En pratique, cela va être une sous-classe ViewHolder, mais en théorie, cela pourrait être à peu près n'importe quoi

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

Vient ensuite une interface qui doit être implémentée par toute vue qui sera utilisée comme enfant immédiat d'un RecyclerView.

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

  public ContextMenuHandler getContextMenuHandler();
}

Ensuite, toute vue qui va créer un menu contextuel en tant qu'enfant d'un RecylcerView doit implémenter ViewWIthContextMenu. Dans mon cas, je n'avais besoin que d'une sous-classe de 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;
  }
}

Et enfin, nous avons besoin d'une classe Fragment renforcée pour intercepter les appels du menu contextuel et les rediriger vers le gestionnaire approprié.

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

Avec tout cela en place, la mise en œuvre finale est assez simple. Le fragment principal doit sous-classer FragmentWithContextMenu. Il configure normalement la RecylerWindow principale et passe à la sous-classe Adapter. La sous-classe Adapter ressemble à

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

C'est à peu près ça. Tout semble fonctionner. Il a mis toutes les classes d'utilitaires dans un package contextmenu séparé afin que j'aie pu donner les noms de classes qui correspondent aux classes qu'il y a sous-classer, mais j'ai pensé que ce serait plus déroutant.

kencorbin
la source
-1

Ok, d'après la réponse de @ Flexo, je vais mettre mPosition à l'ordre ...

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

puis dans onContextItemSelected j'utilise

item.getOrder() 

Et tout fonctionne bien, j'obtiens facilement la position du tableau

windX
la source