RecyclerView onClick

583

Quelqu'un a-t-il RecyclerViewtrouvé un moyen de définir un onClickListenerà des éléments dans le RecyclerView? J'ai pensé à mettre un auditeur sur chacune des mises en page pour chaque élément, mais cela semble un peu trop compliqué, je suis sûr qu'il existe un moyen RecyclerViewd'écouter l' onClickévénement, mais je ne peux pas vraiment le comprendre.

CurtJRees
la source
4
RecyclerViewDemo J'ai trouvé ce projet formidable, en utilisant des interfaces pour fournir plus d'actions gratuites.
MewX
2
consultez ce tutoriel wiki.workassis.com/android-recyclerview-example
Bikesh M
Simple et facile à utiliser - github.com/rahulkapoor1/ClickableAdapter
Rahul
stackoverflow.com/a/31199564/5788247
Shomu

Réponses:

477

Comme les API ont radicalement changé, cela ne m'étonnerait pas que vous créiez un OnClickListenerpour chaque élément. Ce n'est pas si compliqué que ça. Dans votre implémentation de RecyclerView.Adapter<MyViewHolder>, vous devriez avoir:

private final OnClickListener mOnClickListener = new MyOnClickListener();

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
    view.setOnClickListener(mOnClickListener);
    return new MyViewHolder(view);
}

La onClickméthode:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}
nhaarman
la source
32
que faire si je veux supprimer une ligne sur son clic?
Piyush Kukadiya
20
J'aime mieux cette réponse que celle que vous avez liée. Qui veut écrire un écouteur de gestes et une détection de hit box pour gérer cela. Google--
Lo-Tan
17
getChildPosition (view) est une méthode obsolète
Jigar
45
Ça vous dérange de dire dans quelles classes sont vos extraits? onClick(), appartenant à OnClickListenerpeut être attaché à N'IMPORTE QUELLE vue. Toute la question ici est de savoir qui! Veuillez faire un effort, une méthode n'est pas seulement identifiée par un nom, mais aussi au moins par une classe. Si vous ne dites pas que votre code doit être ajouté à l'adaptateur, votre réponse n'aide pas vraiment.
Vince
16
La méthode onClick doit-elle être dans le fragment qui contient RecyclerView? Parce que vous référencez le mRecyclerView dans votre classe MyOnClickListener. Où avez-vous obtenu la référence à cet objet?
Ced
606

Voici une manière meilleure et moins étroitement couplée d'implémenter un OnClickListenerpour un RecyclerView.

Extrait d'utilisation:

RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
    new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {
        // do whatever
      }

      @Override public void onLongItemClick(View view, int position) {
        // do whatever
      }
    })
);

RecyclerItemClickListener la mise en oeuvre:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
  private OnItemClickListener mListener;

  public interface OnItemClickListener {
    public void onItemClick(View view, int position);

    public void onLongItemClick(View view, int position);
  }

  GestureDetector mGestureDetector;

  public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

  @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
      mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
      return true;
    }
    return false;
  }

  @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

  @Override
  public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}
Jacob Tabak
la source
85
Cela ne fournira aucun indice sur le bouton ou la vue (dans l'élément) sur lequel vous avez cliqué. Mais pour le clic global sur l'élément, c'est très bien.
Niranjan
27
Le commentaire de ngen est correct - si vous voulez attacher un écouteur onClick à un élément spécifique dans la vue d'élément, vous devriez probablement le faire dans votre adaptateur, dans onBindViewHolder ou dans votre viewholder lui-même.
Jacob Tabak
16
Un problème avec cette méthode est lorsque vous faites quelque chose qui prend quelques centaines de millisecondes comme démarrer une activité. Lorsque l'élément est cliqué et qu'il a une animation cliquée, il y a un délai notable entre le clic et la visualisation de l'animation.
Gak2
20
Cette solution est extrêmement maladroite, il y a un certain retard dans le traitement du «clic» et la sensation n'est pas seulement correcte
wasyl
6
Quelqu'un pourrait-il m'expliquer pourquoi cette solution avec GestureDetector est censée être une meilleure solution que d'utiliser simplement "setOnClickListener" à l'intérieur de onBindViewHolder () dans l'adaptateur à l'élément correspondant? De cette façon, j'ai au moins besoin de moins de code qu'avec la solution GestureDetector. Merci pour une explication.
e-nature du
115

Je le fais de cette manière, sans classes indues, détecteurs, etc. Code simple à l'intérieur de notre adaptateur. Solution particulièrement meilleure pour longClick qu'auparavant.

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private static ClickListener clickListener;

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
        TextView name;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
            name = (TextView) itemView.findViewById(R.id.card_name);
        }

        @Override
        public void onClick(View v) {
            clickListener.onItemClick(getAdapterPosition(), v);
        }

        @Override
        public boolean onLongClick(View v) {
            clickListener.onItemLongClick(getAdapterPosition(), v);
            return false;
        }
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        PasswordAdapter.clickListener = clickListener;
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Ensuite, à l'intérieur d'un fragment ou d'une activité, appuyez simplement sur:

PasswordAdapter mAdapter = ...;

mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() {
    @Override
    public void onItemClick(int position, View v) {
        Log.d(TAG, "onItemClick position: " + position);
    }

    @Override
    public void onItemLongClick(int position, View v) {
        Log.d(TAG, "onItemLongClick pos = " + position);
    }
});
Marurban
la source
au lieu de OurAdapter.clickListener, je pense que Marurban signifie PasswordAdapter.clickListener et au lieu de TrainingAdapter.ClickListener (), devrait être PasswordAdapter.ClickListener (). A part ça, super solution Marurban! a travaillé pour moi
nommer
L'écouteur onItemClick est également activé lors d'un clic long.
Rashad.Z
10
ViewHolder doit être statique pour de meilleures performances. ce n'est pas une bonne réponse.
Gilberto Ibarra
10
Le clickListener statique crée une fuite de mémoire. Déclarez l'écouteur comme non statique et liez-le au ViewHolder à la place.
BladeCoder
1
@AJW La manière la plus simple consiste à initialiser l'écouteur tôt et à le passer comme argument au constructeur de l'adaptateur puis au constructeur de ViewHolder.
BladeCoder
97

Consultez une question similaire @ CommonsWare commente les liens vers cela , qui implémente l' OnClickListenerinterface dans le viewHolder.

Voici un exemple simple de ViewHolder:

    TextView textView;//declare global with in adapter class

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

      private ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            textView = (TextView)view.findViewById(android.R.id.text1);

      }

      @Override
      public void onClick(View view) {
            Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();

         //go through each item if you have few items within recycler view
        if(getLayoutPosition()==0){
           //Do whatever you want here

        }else if(getLayoutPosition()==1){ 
           //Do whatever you want here         

        }else if(getLayoutPosition()==2){

        }else if(getLayoutPosition()==3){

        }else if(getLayoutPosition()==4){

        }else if(getLayoutPosition()==5){

        }

        //or you can use For loop if you have long list of items. Use its length or size of the list as 
        for(int i = 0; i<exampleList.size(); i++){

        }


      }
  }

Le Adapterressemble alors à ceci:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);

        return new ViewHolder(view);
    }
bolot
la source
14
Cela semble cependant aller dans la mauvaise direction. Si vous devez réutiliser une vue de recyclage dans un autre fragment / activité, l'adaptateur / le viewholder définissent maintenant la logique des clics au lieu de ce qui les contient. Les clics doivent vraiment être traités directement ou indirectement par l'instance conteneur. Il semble qu'un auditeur tactile soit le seul moyen efficace de s'y prendre.
ian.shaun.thomas
18
@tencent Je ne vois pas comment c'est le problème. Si le ViewHolder lui-même contient toutes les informations concernant les données qui sont sélectionnées lorsque l'élément lui-même est cliqué, la seule responsabilité du conteneur est l'affichage de N éléments, plutôt que celui de gérer la sélection d'un i-ème élément spécifique. des N éléments. Cela ListViewétait déjà problématique si vous deviez créer une liste d'objets plus compliqués que de simples lignes. Que faire si vous devez gérer différents événements selon l'endroit où vous cliquez sur l'élément dans ListView? T'es foutu. Ici, vous avez chacun des auditeurs.
EpicPandaForce du
2
Je suis d'accord avec @EpicPandaForce sur celui-ci. Je suis également venu à voter pour cette réponse après avoir lu la section du livre de Commonsware sur la gestion des clics dans RecyclerViews. Cela a très bien fonctionné jusqu'à présent.
AdamMc331
1
findViewById n'est utilisé que lors de la création de la vue ici (d'où onCreateViewHolder). Le support de vue est destiné à empêcher de trouver la vue chaque fois qu'un élément est lié au support, pas lors de la création initiale.
stuckj
2
getPosition()est obsolète, utilisez getAdapterPosition()ou à la getLayoutPosition()place.
K Neeraj Lal
94

Sur la base de la réponse de Jacob Tabak (+1 pour lui), j'ai pu ajouter sur l'auditeur LongClick:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());

        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }
}

Ensuite, vous pouvez l'utiliser comme ceci:

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        // ...
    }

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));
Eng.Fouad
la source
1
Il m'a fallu un certain temps pour m'adapter à mon application et aligner et formater le code aux normes Java / Android, mais finalement cela a bien fonctionné.
milosmns
Comment ajouter une animation pour le clic long?
Jon
1
L'effet de clic @ Eng.Fouad ne fonctionne pas en utilisant cela, bien que si nous définissons l'écouteur de clic dans l'adaptateur, l'effet de clic fonctionne n'importe quelle solution
ingsaurabh
4
Vous devez également remplacerpublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo
Pour une raison quelconque, il ne renvoie pas une vue cliquée. Dans mon cas, je clique sur une case à cocher mais la vue donnée est quelque chose de différent. La façon dont je vérifie:view.getId() == R.id.selection
dVaffection
63

C'est ce qui a fonctionné pour moi. Fixez le OnClickListenerau onBindView. Je ne sais pas vraiment si cela aura un impact sur les performances, mais cela semble fonctionner correctement avec peu de code.

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}
Bubunyo Nyavor
la source
5
dans mon cas holder.itemView.setOnClickListener (..)
D4rWiNS
18
il est nommé 'itemView' au lieu de 'view' dans mon cas, juste pour les débutants, certains d'entre eux ne comprennent pas ce qu'ils copient et ne peuvent pas comprendre pourquoi cela ne fonctionne pas
D4rWiNS
3
C'est la position de mise en page
Bubunyo Nyavor
1
pour moi, cela ne semble s'appliquer qu'au dernier élément visible et non à l'élément cliqué
Nasz Njoka Sr.
2
Cette solution me semble la meilleure, mais en quoi diffère-t-elle de la réponse de @bolot en termes de performances? Il a implémenté View.OnClickListener directement sur la classe ViewHolder, qui crache séparément la méthode onClick. Quelle serait la meilleure solution?
Edmond Tamas du
46

C'était si difficile pour moi d'avoir sur l'écouteur de clic d'élément dans l'activité et aussi d'avoir l'écouteur de clic pour une vue unique de l'élément qui ne se déclenchera pas sur l'écouteur de clic d'élément. Après avoir joué avec la réponse de Jacob Tabak, je respecte sa réponse pour le clic sur l'élément si aucune autre action tactile à l'intérieur de l'élément n'est présentée.

J'ai une OnClickListenerinterface personnalisée qui a un événement de clic sur l'élément qui contient la vue de l'élément cliqué et la position de l'élément depuis l'adaptateur. J'en présente une instance dans le constructeur (ou cela peut être avec setter) et je l'attache à l'écouteur de clic du conteneur du support de vue.

J'ai également un autre écouteur de clic dans l'adaptateur (peut être dans le support de vue) qui gérera le clic de vue actuel du conteneur.

 public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {

private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;

public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}

public MyRecyclerAdapter(ArrayList<String> itemsData,
        OnItemClickListener onItemClickListener) {
    mOnItemClickListener = onItemClickListener;
    this.mData = itemsData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {

    View layoutView = LayoutInflater.from(mContext).inflate(
            R.layout.list_item, parent, false);

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
        }
    });

    viewHоlder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do button click work here with
            // mData.get( viewHolder.getAdapterPosition() );
        }
    });

    return viewHolder;
}

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

Dans l'activité, vous devez initialiser l'adaptateur en passant l'instance du OnItemClickListener

public class FeedActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    .....

    MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() {

        @Override
        public void onItemClick(View view, int position) {

            ///list item was clicked
        }
    });

    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(mFeedsAdapter);
}

Et mon ViewHolder

public class MyViewHolder extends RecyclerView.ViewHolder {

public Button button;
public View container;

public MyViewHolder(View itemLayoutView) {
    super(itemLayoutView);

    container = itemLayoutView;
    button = (Button) itemLayoutView.findViewById(R.id.button);
}}
Sir NIkolay Cesar The First
la source
Cette approche a bien fonctionné pour moi - cela signifie que vous pouvez gérer les clics dans l'activité plutôt que dans la vue de la grille
coupe
3
Où puis-je vous donner de l'argent. 4 heures de recherche puis j'ai lu votre post. Merci pour le temps que vous avez pris pour poster ceci.
Brandon
3
Cela semble stupide, mais cela a-t-il un problème de mémoire ou d'efficacité? Parce que nous affectons l'écouteur de clics à chaque fois qu'une vue est dessinée, n'est-ce pas?
rgv
1
@Raghav yes à chaque fois que la vue est liée, un nouvel écouteur de clic est affecté, mais il s'agit du flux standard. Mais le mOnItemClickListener est créé une seule fois pour l'adaptateur, la vue et sa position sont différentes à chaque clic sur un élément;)
Sir NIkolay Cesar Le premier
3
Excellent exemple pour tuer les performances des applications et créer une utilisation excessive de la mémoire! Avec cet exemple, il vous suffit de faire défiler pour créer des centaines d'objets inutiles qui, dans un instant, seront inutiles et devront être accessibles en tant que garbige. @NoobDogg a raison. Aucun ClickListeners ne doit être créé sur onBindView. Un écouteur de clics doit être créé une fois dans onCreateView (ou constructeur de titulaire), et existe pendant que nous avons besoin d'un écran avec cet adaptateur.
Mykola Tychyna
36

C'est ce dont j'ai fini par avoir besoin, au cas où quelqu'un le trouverait utile:

public static class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View item) {

        super(item);
        item.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("RecyclerView", "onClick:" + getAdapterPosition());
            }
        });

    }
}

Source: http://blog.csdn.net/jwzhangjie/article/details/36868515

Fifer Sheep
la source
De toutes les versions que j'ai essayées, c'est celle sur laquelle j'ai travaillé. Mais est-ce correct de le faire de cette façon? Ou existe-t-il un meilleur moyen, comme les meilleures pratiques?
Matthias Loibl
1
Pour autant que je sache, c'était le seul moyen. Vérifiez ceci pour plus de détails! stackoverflow.com/a/24933117/1508887
Fifer Sheep
Comment puis-je ouvrir un nouveau fragment depuis la méthode onclick interne?
hachage
5
getAdapterPosition () remplace getPosition ()
Kennedy Nyaga
27

Je solution agréable pour RecyclerView« s onItemClickListenerpour les articles et les sous - éléments

Étape 1- Créer une interface

public interface OnRecyclerViewItemClickListener
{
    /**
     * Called when any item with in recyclerview or any item with in item
     * clicked
     * 
     * @param position
     *            The position of the item
     * @param id
     *            The id of the view which is clicked with in the item or
     *            -1 if the item itself clicked
     */
    public void onRecyclerViewItemClicked(int position, int id);
}

Étape 2- Ensuite, utilisez-la dans la onBindViewHolderméthode de l'adaptateur de la manière suivante

/**
     * Custom created method for Setting the item click listener for the items and items with in items
     * @param listener OnRecyclerViewItemClickListener 
     */
    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
    {
        this.listener = listener;
    }

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

        // viewHolder.albumBg.setBackgroundResource(_itemData[position]
        // .getImageUrl());

        viewHolder.albumName.setText(arrayList.get(position).getName());
        viewHolder.artistName.setText(arrayList.get(position).getArtistName());
        String imgUrl = arrayList.get(position).getThumbImageUrl();

        makeImageRequest(imgUrl, viewHolder);
        viewHolder.parentView.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, -1);
            }
        });
        viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, v.getId());
            }
        });

    }

    // class to hold a reference to each item of RecyclerView
    public static class ViewHolder extends RecyclerView.ViewHolder
    {

        public TextView albumName, artistName;
        public ImageView albumIcon, settingButton;
        public LinearLayout parentView;

        public ViewHolder(View itemLayoutView)
        {
            super(itemLayoutView);
            // albumBg = (LinearLayout) itemLayoutView
            // .findViewById(R.id.albumDlbg);
            albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
            artistName = (TextView) itemLayoutView
                    .findViewById(R.id.artistName);
            albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
            parentView = (LinearLayout) itemLayoutView
                    .findViewById(R.id.albumDlbg);
            settingButton = (ImageView) itemLayoutView
                    .findViewById(R.id.settingBtn);
        }

    }

Étape 3: recherchez et configurez la vue du recycleur dans l'activité ou le fragment où vous l'utilisez

recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);

        lm = new LinearLayoutManager(mActivity);
        lm.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(lm);
        recyclerView.addItemDecoration(
                new HorizontalDividerItemDecoration.Builder(getActivity())
                        .paint(Utils.getPaint()).build());
        PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
                mActivity, true);
        // set adapter
        recyclerView.setAdapter(mAdapter);
        mAdapter.setOnItemClickListener(this);
        // set item animator to DefaultAnimator
        recyclerView.setItemAnimator(new DefaultItemAnimator());

Étape 4 - Enfin, implémentez l'interface dans l'activité ou le fragment où vous utilisez la vue de recyclage

@Override
    public void onRecyclerViewItemClicked(int position, int id)
    {
        if(id==-1){
            Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
        }
    }
Gopal Singh Sirvi
la source
2
C'est la meilleure solution car nous avons généralement besoin de beaucoup de propriétés d'activité / fragment sur notre onItemClickListener, et il n'y a aucun sens de l'appeler directement depuis le viewholder (je devrais créer un constructeur personnalisé pour chaque adaptateur). Par ailleurs, votre code est un peu étendu, je vous suggère de le couper à la partie la plus importante (setOnItemClickListener).
sagits
il s'agit d'une bonne approche simple pour différencier la ligne / l'élément des sous-éléments
Nigel Savage
17

Voici ce que j'ai fait. Cette solution prend en charge à la fois onClick et onLongClick sur les éléments RecyclerView et les vues à l'intérieur des éléments RecyclerView (vues internes).

Je marque viewHolder sur les vues de mon choix:

public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
    ViewHolder viewHolder = new ViewHolder(itemView);

    itemView.setOnClickListener( this);
    itemView.setOnLongClickListener(this);
    viewHolder.imageIV.setOnClickListener(this);
    viewHolder.imageIV.setOnLongClickListener(this);

    viewHolder.imageIV.setTag(viewHolder);
    itemView.setTag(viewHolder);

    return viewHolder;
}

Et j'utilise holder.getPosition () pour récupérer la position dans la méthode onClick () (onLongClick est similaire):

public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    int position = holder.getPosition();

    if (view.getId() == holder.imageIV.getId()){
        Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
    }
}

Une variante avec getChildPosition fonctionne également. Veuillez noter que pour les vues internes, dans onClick (), utilisez:

int position = recyclerView.getChildPosition((View)view.getParent());

À mon avis, l'avantage de cette solution est que lorsque l'on clique sur l'image, seul l'écouteur d'image onclick () est appelé alors que lorsque j'ai combiné la solution de Jacob pour une vue d'élément RecyclerView et ma solution pour les vues internes, la vue d'élément RecyclerView onclick ( ) est également appelé (lorsque vous cliquez sur l'image).

u2gilles
la source
11

Il existe un moyen beaucoup plus simple de procéder. Il suffit d'appliquer en cliquant onBindViewHoldersur la vue racine.

Considérez que c'est votre point de vue pour l'adaptateur,

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1dp"
            android:textSize="15sp" />
</LinearLayout>

Ensuite, procédez comme suit dans votre adaptateur

//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
    ViewHolder1 viewHolder = new ViewHolder1(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {

    //apply on click on your root view
    holder.linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Do on click stuff
        }
    });
}

//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

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

        this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
        this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
    }
}
Sushant
la source
9

Vous pouvez passer un clickListenerà Adapter.

Dans votre Activity:

private View.OnClickListener mItemClick = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent intent = null;
        int position = list.getChildPosition(v);
        switch (position) {
            case 0:
                intent = new Intent(MainActivity.this, LeakCanaryActivity.class);
                break;
            case 1:
                intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class);
                break;
        }
        if (intent != null) {
            MainActivity.this.startActivity(intent);
        }
    }
};

puis passez-le à Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

Dans Adapter« s onCreateViewHolder:

 @Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
    View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
    ViewHolder holder = new ViewHolder(itemView);
    itemView.setOnClickListener(mItemClick);
    return holder;
}
Francis Shi
la source
Comment transmettez-vous les holdervaleurs par intention?
RoCk RoCk
8

J'ai développé une bibliothèque légère pour Android, vous pouvez visiter https://github.com/ChathuraHettiarachchi/RecycleClick

et suivez pour l'échantillon suivant

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });
Chathura Jayanath
la source
Peut confirmer, cette bibliothèque est géniale! Très facile à utiliser, bon travail!
peterkodermac
7

Vous pouvez implémenter OnClickListener à votre classe ViewHolder

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public Item item
        @InjectView(R.id.tv_title)
        public TextView tvTitle;
        @InjectView(R.id.rl_row)
        public RelativeLayout rlRow;

        public ViewHolder(View v) {
            super(v);
            ButterKnife.inject(this, v);
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            Log.e("item title",item.getTitle());
        }
    }

Et onBindViewHolder définit l'élément de votre porte-vue

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }
population
la source
7

Trop simple et efficace.

Au lieu d'implémenter l'interface View.OnClickListenerdans le support de vue ou de créer et d'interfacer et d'implémenter l'interface dans votre activité - j'ai utilisé ce code pour une OnClickListenerimplémentation simple .

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

        // Your initializations goes here...
        private List<String> mValues;

        public static class ViewHolder extends RecyclerView.ViewHolder {

            //create a variable mView
            public final View mView;

            /*All your row widgets goes here
            public final ImageView mImageView;
            public final TextView mTextView;*/

            public ViewHolder(View view) {
                super(view);
                //Initialize it here
                mView = view;

                /* your row widgets initializations goes here
                mImageView = (ImageView) view.findViewById(R.id.avatar);
                mTextView = (TextView) view.findViewById(android.R.id.text1);*/
            }
        }

        public String getValueAt(int position) {
            return mValues.get(position);
        }

        public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {

            mBackground = mTypedValue.resourceId;
            mValues = items;
        }

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

        @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
            holder.mBoundString = mValues.get(position);
            holder.mTextView.setText(mValues.get(position));

            //Here it is simply write onItemClick listener here
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Context context = v.getContext();
                    Intent intent = new Intent(context, ExampleActivity.class);

                    context.startActivity(intent);
                }
            });
        }

        @Override
        public int getItemCount() {
            return mValues.size();
        }
    }
Manikanta
la source
3
Il s'agit d'une mauvaise pratique courante car elle semble beaucoup trop facile. Vous créez un nouvel écouteur interne chaque fois qu'un objet est lié (et chaque élément dans un recycleur peut être lié de nombreuses fois), ce qui est mauvais pour a) les performances b) la collecte des ordures. Au lieu de cela, vous devez créer UN écouteur quelque part (dans le viewholder, dans l'adaptateur, dans le fragment supérieur ou l'activité) et l'ajouter simplement aux éléments dans le constructeur du viewholder dans onCreateViewHolder. Cela a la complexité supplémentaire d'avoir à déterminer quel élément était un clicker, mais peut être résolu facilement via des balises ou en ajoutant plus d'informations au support.
GuillermoMP
6

Toutes les réponses publiées jusqu'à présent sont d'excellentes solutions, mais si vous ne voulez pas traiter trop de détails d'implémentation et que cela fonctionne simplement de la même manière que ListView, je recommanderais d'utiliser TwoWay-View, comme on le voit ici:

https://github.com/lucasr/twoway-view

Notez que cette implémentation prend également en charge la pression longue sur les éléments, ainsi que la prise en charge des états pressés (ce qui est quelque chose d'important que les autres solutions à cette question manquent).

Si vous ne souhaitez pas utiliser la bibliothèque entière, jetez un œil à la classe ClickItemTouchListener , qui peut être utilisée de manière autonome si nécessaire. Le seul problème que j'ai trouvé en ce moment est avec un appui long + défilement, il semble avoir un comportement incorrect.

Jawnnypoo
la source
6

Si vous souhaitez intercepter l'événement Click sur des éléments individuels, implémentez simplement OnClickListeneren ViewHolderclasse, puis définissez les écouteurs de clic sur des vues individuelles ou dans leur ensemble itemView.

L'exemple suivant montre la même chose

public  class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener
    {
        TextView txt_title,txt_name,txt_email;

        public ContactViewHolder(View itemView) 
        {
            super(itemView);
            txt_title = (TextView)itemView.findViewById(R.id.txt_title);
            txt_name  = (TextView)itemView.findViewById(R.id.txt_name);
            txt_email = (TextView)itemView.findViewById(R.id.txt_email);

            txt_name.setOnClickListener(this);
            txt_email.setOnClickListener(this);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if(v == itemView)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_name)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_email)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show();
            }
        }

    }
} 
HemangNirmal
la source
5

Pour moi, c'est la meilleure façon:

class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener { 
  ...
  @Override
  public void onClick(View view) {
        int itemPosition = vRecycle.getChildPosition(view);
        //And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback
    }
  ...
}
4gus71n
la source
3
getChildPosition () est décapité
Nasz Njoka Sr.
5

Le RecyclerViewn'a pas OnClickListeneret devra le mettre en œuvre nous-mêmes.

J'aime ajouter une OnItemClickListenerinterface Adapteravec une onClickméthode invoquée lorsque vous cliquez sur la vue de l'élément dans le ViewHolder. Ainsi, la responsabilité de gérer le clic sur un élément est en dehors du ViewHolderetAdapter . L'activité ou le fragment qui décidera quoi faire

Ajoutez une interface à l'écouteur et à l'objet écouteur.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...
}

Nous capturons le clic de la vue racine de l'élément et lorsque le rappel est déclenché, l' onClickécouteur appelle sur l'adaptateur.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...

  public static class ViewHolder extends RecyclerView.ViewHolder {
      public ImageView imageView;

      public ViewHolder(View itemRootView) {
          super(itemRootView);
          imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);

          itemRootView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  int position  = ViewHolder.super.getAdapterPosition();
                  onItemClickListener.onItemClick(view,position);
              }
          });
      }
  }
}

Puisque l'activité ou le fragment, fragment dans notre cas, nous affectons un écouteur à l'adaptateur et le rappel onClick nous obtiendrons l'élément sélectionné par position et ouvrirons une activité détaillée de l'élément.

public class ItemsFragment extends Fragment {
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       ...    
        ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //Do something when an item has been clicked
            }
        });
        ...
    }
...
}
xurxodev
la source
5

Malheureusement, il RecyclerViewmanque quelques fonctionnalités ListViewintégrées. Par exemple, la possibilité d'ajouter OnItemClickListenerun élément qui se déclenche lorsqu'un élément est cliqué. RecyclerViewvous permet de définir un OnClickListenerdans votre adaptateur, mais la transmission de cet écouteur de clics à partir de votre code d'appel, à l'adaptateur et au ViewHolder, est compliquée pour intercepter un simple clic d'élément.

public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
    }
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        if (mOnItemLongClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
        return false;
    }
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
        = new RecyclerView.OnChildAttachStateChangeListener() {
    @Override
    public void onChildViewAttachedToWindow(View view) {
        if (mOnItemClickListener != null) {
            view.setOnClickListener(mOnClickListener);
        }
        if (mOnItemLongClickListener != null) {
            view.setOnLongClickListener(mOnLongClickListener);
        }
    }

    @Override
    public void onChildViewDetachedFromWindow(View view) {

    }
};

private ItemClickSupport(RecyclerView recyclerView) {
    mRecyclerView = recyclerView;
    mRecyclerView.setTag(R.id.item_click_support, this);
    mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support == null) {
        support = new ItemClickSupport(view);
    }
    return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support != null) {
        support.detach(view);
    }
    return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
    return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
    mOnItemLongClickListener = listener;
    return this;
}

private void detach(RecyclerView view) {
    view.removeOnChildAttachStateChangeListener(mAttachListener);
    view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {

    void onItemClicked(RecyclerView recyclerView, int position, View v);
}

public interface OnItemLongClickListener {

    boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}

Vous devez également définir à l' R.id.item_click_supportaide d'ids.xml:

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
  <item name="item_click_support" type="id" />
 </resources>

L'écouteur de clic de code résultant ressemble maintenant à ceci:

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
    // do it
}
});

Pour une brève explication sur les clics de recyclage, veuillez consulter ce petit blog

anand krish
la source
5

vous pouvez facilement définir setOnClickListener dans votre classe ViewHolder comme suit:

public class ViewHolder extends RecyclerView.ViewHolder {
    TextView product_name;

    ViewHolder(View itemView) {
        super(itemView);
        product_name = (TextView) itemView.findViewById(R.id.product_name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int itemPosition = getLayoutPosition();
                Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show();
            }
        });
    }
}
Arash Hatami
la source
5

Voici ce que j'ai fait En savoir plus et télécharger l'essentiel ici

Ajout du même ici

CustomItemClickListener.java

public interface CustomItemClickListener {
 public void onItemClick(View v, int position);
}

ItemsListAdapter.java

public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;

Context mContext;
CustomItemClickListener listener;

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
    final ViewHolder mViewHolder = new ViewHolder(mView);
    mView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            listener.onItemClick(v, mViewHolder.getAdapterPosition());
        }
    });
    return mViewHolder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle()));
    if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) {
      // I Love picasso library :) http://square.github.io/picasso/
        Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image).
                placeholder(R.drawable.ic_no_image).
                transform(new RoundedCornersTransformation(5, 0)).
                into(holder.thumbnailImage);
    } else {
        holder.thumbnailImage.setImageResource(R.drawable.ic_no_image);
    }
}


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

public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) {
    this.data = data;
    this.mContext = mContext;
    this.listener = listener;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView itemTitle;
    public ImageView thumbnailImage;

    ViewHolder(View v) {
        super(v);
        itemTitle = (TextView) v
                .findViewById(R.id.post_title);
        thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image);
    }
 }
}
Muhammad Riyaz
la source
4

D'après la plupart des réponses ci-dessus, ils semblent définir leurs écouteurs onclick sur des éléments individuels. Cependant, la solution que je suis sur le point d'offrir est très simple mais pas intuitive pour beaucoup. Beaucoup oublient que les autres composants sont toujours dans un composant parent qui est utilisé pour afficher les éléments dans les vues Liste ou Recycleur. Cette solution consiste simplement à définir un seul écouteur onclick sur cette vue parent et le tour est joué. La solution comprend également un moyen de transmettre la position de l'élément cliqué dans la liste ou la vue du recycleur. Ici, notre rootview principal est un CardView de la bibliothèque de support Android. Voici un exemple de code

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

public static final String LOG_TAG = ListAdapter.class.getSimpleName();
private Cursor mDataset;
private Context mContext;
private ViewHolder mViewHolder;

// Provide a suitable constructor (depends on the kind of dataset)
public ListAdapter(Context context, Cursor Dataset) {
    mDataset = Dataset;
    mContext = context;
}

// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // create a new view
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.list_business_view, parent, false);

    mViewHolder = new ViewHolder(v);
    return mViewHolder;
}

public void setData(Cursor newdata) {
    this.mDataset = newdata;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Bind data to other items here. To save time, i have ommited that.
           //here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item.
            holder.card.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show();

            }
        });

    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    if (null != mDataset) {
        return mDataset.getCount();
    }
    return 0;

}


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
    // each data item is just a string in this case
    public final TextView mBusinesssName; // View for the business name
    public final TextView mBusinessCategory; //View for the category name
    public final ImageView businessImage; // View for the business category image Image
    public final TextView mBusinessDistance; // View for the distance
    public final CardView card;

    public ViewHolder(View view) {
        super(view);
        mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview);
        mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview);
        mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview);
        businessImage = (ImageView) view.findViewById(R.id.list_item_icon);
        card = (CardView) view.findViewById(R.id.card_view);

    }
}
}
larrytech
la source
4

Mise en œuvre Kotlin de la réponse de Nhaarman :

mRecyclerView.addOnItemTouchListener(object  : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
            override fun onItemClick(view: View, position: Int) {

            }

            override fun onLongItemClick(view: View?, position: Int) {

            }
}){})

RecyclerItemClickListener.java:

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View


open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {

    private var mGestureDetector: GestureDetector

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)

        fun onLongItemClick(view: View?, position: Int)
    }

    init {
        mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent): Boolean {
                return true
            }

            override fun onLongPress(e: MotionEvent) {
                val child = recyclerView.findChildViewUnder(e.x, e.y)
                if (child != null && mListener != null) {
                    mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
                }
            }
        })
    }

    override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
        val childView = view.findChildViewUnder(e.x, e.y)
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
            return true
        }
        return false
    }

    override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
Nilesh Deokar
la source
3
public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, year, genre;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            genre = (TextView) view.findViewById(R.id.genre);
            year = (TextView) view.findViewById(R.id.year);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
Exception de pointeur nul
la source
3

voici le code complet pour mon adaptateur personnalisé ce code gonflera les lignes avec les éléments de liste définis dans le fichier xml nommé "list_item" il effectuera également un événement de clic sur toutes les lignes des éléments de liste avec les positions respectives.

public class MyCustomAdapter extends RecyclerView.Adapter`<`AdapterMyCustomAdapter.ViewHolder> {

    public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
        public onItemClickListener mListener;
        public ViewHolder(View v, onItemClickListener listener) {
            super(v);
            mListener =listener;
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            mListener.onRecyclerItemClick(v, getPosition());
        }

        public static interface onItemClickListener {
            public void onRecyclerItemClick(View view , int position);
        }
    }

    @Override
    public int getItemCount() {
        return 5;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int pos) {      

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

    /* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/

        MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {

            @Override
            public void onRecyclerItemClick(View view, int position) {
                System.out.println("clicked on list item at position " +position);
            } 
        });
        return vh;
    }
}
Lone_iqbal
la source
2

Nous pouvons le faire en utilisant des références faibles Java. Sémantiquement, le détenteur de la vue est celui qui doit répondre à l'événement click ou le déléguer au répondeur correct.

Nos buts:

  1. Le Viewholder ne doit rien savoir de la classe qui répond aux événements, sauf qu'il implémente une certaine interface.
  2. Le gestionnaire de clics doit obtenir la position dans la vue Recycler de la vue sur laquelle vous avez cliqué.
  3. Nous devrions pouvoir discerner quelle vue a été cliquée dans le support de vue.
  4. Maintenez le couplage lâche entre tous les composants et ne provoquez aucun cycle de rétention.

Pas:

  1. Créez une interface pour gérer les réponses aux clics.

  2. Implémentez cette interface dans l'activité qui gérera le clic.

  3. Ajoutez une variable membre dans l'adaptateur RecyclerView pour contenir la référence faible et un constructeur qui la définit.

  4. Faites de même dans RecyclerView ViewHolder et ajoutez une variable membre pour garder une trace de la position.

  5. Définissez vos écouteurs au clic sur n'importe quelle vue que vous souhaitez dans le ViewHolder, puis rappelez au répondeur pour les gérer.

  6. Modifiez votre méthode onBindViewHolder pour définir la position lors de la liaison.

  7. Transmettez le répondeur au ViewHolder.

  8. Dans le répondeur, vous pouvez maintenant utiliser getId () sur la vue pour déterminer quelle vue a été cliquée.

Et voici un Gist afin que vous puissiez voir comment tout cela s'imbrique: Gestion des clics RecyclerView

Rajiev Timal
la source
2

Je suis conscient qu'il y a beaucoup de réponses, mais je pensais que je pourrais également en fournir la mise en œuvre. (Tous les détails peuvent être trouvés sur une autre question à laquelle j'ai répondu ).

Ainsi, pour ajouter un écouteur de clics, votre ViewHolderclasse interne doit être implémentée View.OnClickListener. Cela est dû au fait que vous définirez un OnClickListenersur le itemViewparamètre du ViewHolderconstructeur de. Permettez-moi de vous montrer ce que je veux dire:

public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

Les seules autres choses que vous devez ajouter sont une interface personnalisée pour votre Adapteret une méthode de définition:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

Votre nouvelle prise en charge des clics Adapterest donc terminée.

Maintenant, utilisons-le ...

    ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
    clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
        @Override
        public void onEntryClick(View view, int position) {
            // stuff that will happen when a list item is clicked
        }
    });

C'est essentiellement la façon dont vous configurez une normale Adapter, sauf que vous utilisez votre méthode de définition que vous avez créée pour contrôler ce que vous ferez lorsque votre utilisateur cliquera sur un élément de liste particulier.

Vous pouvez également consulter un ensemble d'exemples que j'ai faits sur ce Gist sur GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

Farbod Salamat-Zadeh
la source
Vous devez utiliser getAdapterPosition () au lieu de getLayoutPosition ()
BladeCoder
2

Voici ce que je fais pour réutiliser OnClickListener

  public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyviewHolder>
                                         implements View.OnClickListener

dans ViewHoder Prendre le parent de l'élément

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

        public MyviewHolder(View itemView) {
            super(itemView);
            linearLayout_item=itemView.findViewById(R.id.linearLayout_item);
        }
    }

dans la balise onBindViewHolder définie comme position

   @Override
    public void onBindViewHolder(MyviewHolder holder, int position) {

       holder.linearLayout_item.setTag(position);
       holder.linearLayout_item.setOnClickListener(this);
    }

et dans Onclick

 @Override
public void onClick(View v) {

    int position = (int) v.getTag();
    switch (v.getId()) {
        case R.id.linearLayout_item:

            // do some thing with position 

            break;
    }
}
Manohar Reddy
la source
2

Pour moi, la façon la plus simple de le faire est celle-ci.

Constructeur d'adaptateur

private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter<EnvironmentTypeRecyclerViewAdapter.ViewHolder>
{
     private final EnvironmentTypeRecyclerViewAdapterListener mEnvironmentTypeRecyclerViewAdapterListener;
     private List<Environment> mEnvironmentsData;

     public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
     {
         public ViewHolder(View v)
         {
             super(v);
             v.setOnClickListener(this);

         }

         @Override
         public void onClick(View v)
         {
              Environment environment = mEnvironmentsData.get(getAdapterPosition());
              if (mEnvironmentTypeRecyclerViewAdapterListener != null && environment != null) {
                      mEnvironmentTypeRecyclerViewAdapterListener.onListItemSelected(environment);      
              }
        }

        public EnvironmentTypeRecyclerViewAdapter(List<SmallCellEnvironment> environments, EnvironmentTypeRecyclerViewAdapterListener environmentTypeRecyclerViewAdapterListener)
        {
            mEnvironmentTypeRecyclerViewAdapterListener = environmentTypeRecyclerViewAdapterListener;
            mEnvironmentsData = environments;
        }
}

L'interface liée

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
Jérémie Petitjean
la source