RecyclerView onClick

583

¿Alguien ha RecyclerViewencontrado una manera de establecer un onClickListenerelemento en el RecyclerView? Pensé en configurar un oyente para cada uno de los diseños para cada elemento, pero eso parece demasiado complicado, estoy seguro de que hay una manera de RecyclerViewescuchar el onClickevento, pero no puedo entenderlo.

CurtJRees
fuente
44
RecyclerViewDemo Me pareció genial este proyecto, usando interfaces para proporcionar más acciones gratuitas.
MewX
2
mira
Bikesh M
Simple y fácil de usar - github.com/rahulkapoor1/ClickableAdapter
Rahul
stackoverflow.com/a/31199564/5788247
Shomu

Respuestas:

477

Como las API han cambiado radicalmente, no me sorprendería si creara una OnClickListenerpara cada elemento. Sin embargo, no es una molestia. En su implementación de RecyclerView.Adapter<MyViewHolder>, debe tener:

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

El onClickmétodo:

@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
fuente
32
¿Qué pasa si quiero eliminar una fila en su clic?
Piyush Kukadiya
20
Me gusta esta respuesta mejor que la que vinculaste. ¿Quién quiere escribir un detector de gestos y detección de cuadro de golpe para manejar esto? Google--
Lo-Tan
17
getChildPosition (view) es un método obsoleto
Jigar
45
¿Te importaría decir en qué clases están tus fragmentos? onClick(), perteneciente a OnClickListenerse puede adjuntar a CUALQUIER vista. ¡Toda la pregunta aquí es cuál! Haga un esfuerzo, un método no solo se identifica por un nombre, sino también al menos por una clase. Si no dice que su código debe agregarse al adaptador, su respuesta realmente no ayuda.
Vince
16
¿Debería el método onClick estar en el fragmento que contiene el RecyclerView? Porque hace referencia a mRecyclerView en su clase MyOnClickListener. ¿De dónde sacaste la referencia a ese objeto?
Ced
606

Aquí hay una forma mejor y menos acoplada de implementar un OnClickListenerpara a RecyclerView.

Fragmento de uso:

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 implementación:

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
fuente
85
Esto no proporcionará ninguna pista sobre qué botón o vista (dentro del elemento) se hizo clic. Pero para hacer clic en el artículo en general, está bien.
Niranjan
27
El comentario de ngen es correcto: si desea adjuntar un oyente onClick a un elemento específico dentro de la vista del elemento, probablemente debería hacerlo en su adaptador, en onBindViewHolder o en su propio marcador de vista.
Jacob Tabak
16
Un problema con este método es cuando estás haciendo algo que lleva unos cientos de milisegundos, como comenzar una actividad. Cuando se hace clic en el elemento y tiene una animación en la que se hace clic, hay un retraso notable entre hacer clic y ver la animación.
Gak2
20
Esta solución se siente extremadamente torpe, hay un retraso al procesar el 'clic' y la sensación no es solo correcta
wasyl
66
¿Podría alguien explicarme por qué se supone que esta solución con GestureDetector es una mejor solución que simplemente usar "setOnClickListener" dentro de onBindViewHolder () en el adaptador para el elemento correspondiente? De esta manera, al menos, necesito menos código que con la solución GestureDetector. Gracias por una explicación
e-nature
115

Lo hago de esta manera, sin clases indebidas, detectores, etc. Código simple dentro de nuestro adaptador. Solución especialmente mejor para longClick que la presentada anteriormente.

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

Luego dentro del fragmento o actividad, simplemente presione:

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
fuente
en lugar de OurAdapter.clickListener, creo que Marurban significa PasswordAdapter.clickListener y en lugar de TrainingAdapter.ClickListener (), debería ser PasswordAdapter.ClickListener (). Aparte de eso, gran solución Marurban! funcionó para mí
nommer
El oyente onItemClick también se activa con un clic largo.
Rashad.Z
10
ViewHolder debe ser estático para el mejor rendimiento. Esta no es una buena respuesta.
Gilberto Ibarra
10
El clickListener estático crea una pérdida de memoria. Declare al oyente como no estático y, en su lugar, enlácelo al ViewHolder.
BladeCoder
1
@AJW La forma más simple es inicializar el escucha temprano y pasarlo como argumento al constructor del Adaptador y luego al constructor ViewHolder.
BladeCoder
97

Vea una pregunta similar en los enlaces de comentarios de @ CommonsWare a esto , que implementa la OnClickListenerinterfaz en el viewHolder.

Aquí hay un ejemplo 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++){

        }


      }
  }

El Adapterentonces se ve así:

    @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
fuente
14
Sin embargo, esto parece ir en la dirección equivocada. Si necesita reutilizar una vista de reciclador en otro fragmento / actividad, el adaptador / marcador de vista ahora está definiendo la lógica de los clics en lugar de lo que los contiene. Los clics realmente deberían ser manejados directa o indirectamente por la instancia que los contiene. Parece que un oyente táctil es la única forma efectiva de hacerlo.
ian.shaun.thomas
18
@tencent No veo cómo ese es el problema. Si el ViewHolder contiene toda la información con respecto a qué datos se seleccionan cuando se hace clic en el elemento en sí, entonces la única responsabilidad del contenedor es la visualización de N elementos, en lugar de manejar la selección de un elemento i-ésimo específico. de los N elementos. Esto ListViewya era problemático si tenía que crear una lista de objetos más complicados que simples filas. ¿Qué sucede si necesita manejar diferentes eventos dependiendo de dónde haga clic en el elemento en ListView? Estás jodido. Aquí tienes cada oyente.
EpicPandaForce
2
Estoy de acuerdo con @EpicPandaForce en este caso. También vine a votar esta respuesta después de leer la sección del libro de Commonsware sobre el manejo de clics en RecyclerViews. Hasta ahora me ha funcionado muy bien.
AdamMc331
1
findViewById solo se usa en la creación del titular de la vista aquí (de ahí onCreateViewHolder). El titular de la vista está destinado a evitar encontrar la vista cada vez que un elemento está vinculado al titular, no en la creación inicial.
stuckj
2
getPosition()está en desuso, uso getAdapterPosition()o en su getLayoutPosition()lugar.
K Neeraj Lal
94

Basado en la respuesta de Jacob Tabak (+1 para él), pude agregar a LongLick oyente:

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

Entonces puedes usarlo así:

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
fuente
1
Me tomó un tiempo adaptarme a mi aplicación y alinear y formatear el código con los estándares Java / Android, pero finalmente funcionó bien.
milosmns
¿Cómo se agrega una animación para el clic largo?
Jon
1
@ Eng.Fouad click effect no funciona usando esto, aunque si configuramos click listener en adaptador click click funciona cualquier solución para esto
ingsaurabh
44
También debe anularpublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo
Por alguna razón, no devuelve una vista cliqueada. En mi caso, hago clic en una casilla de verificación, pero la vista dada es algo diferente. La forma en que view.getId() == R.id.selection
reviso
63

Esto es lo que funcionó para mí. Adjunte el OnClickListenera la onBindView. Realmente no sé si esto afectará el rendimiento, pero parece funcionar bien con poco código.

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
fuente
55
en mi caso holder.itemView.setOnClickListener (..)
D4rWiNS
18
en mi caso se llama 'itemView' en lugar de 'view', solo para los principiantes, algunos de ellos no entienden lo que están copiando y no pueden entender por qué no funciona
D4rWiNS
3
Es la posición de diseño
Bubunyo Nyavor
1
para mí, esto parece aplicarse solo para el último elemento visible, no para el elemento seleccionado
Nasz Njoka Sr.
2
Esta solución me parece la mejor, pero ¿cómo difiere esto de la respuesta de @bolot en términos de rendimiento? Ha implementado View.OnClickListener directamente en la clase ViewHolder, que luego escupe el método onClick por separado. ¿Cuál sería la mejor solución?
Edmond Tamas
46

Esto fue muy difícil para mí tener un elemento de escucha de clics en la actividad y también tener un elemento de escucha de clics para una vista única del elemento que no se activará en el elemento de escucha de clics. Después de jugar con la respuesta de Jacob Tabak, respeto su respuesta al hacer clic en el elemento si no se presentan otras acciones táctiles dentro del elemento.

Tengo una OnClickListenerinterfaz personalizada que tiene un evento de clic de elemento que contiene la vista del elemento seleccionado y la posición del elemento desde el adaptador. Presento una instancia de él en el constructor (o puede ser con setter) y lo adjunto al contenedor de vistas, haga clic en el oyente de escucha.

También tengo otro detector de clics en el adaptador (puede estar en el soporte de la vista) que manejará el clic de vista actual desde el contenedor.

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

En la actividad, debe inicializar el adaptador pasando la instancia de 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);
}

Y mi 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 el primero
fuente
Este enfoque ha funcionado bien para mí - que significa que puede manejar clics en la actividad en lugar de dentro de la vista de cuadrícula
leafcutter
3
¿Dónde puedo darte dinero? 4 horas de búsqueda y luego leí tu publicación. Gracias por el tiempo que te tomaste para publicar esto.
Brandon
3
Esto suena estúpido pero, ¿tiene algún problema de memoria o eficiencia? Porque estamos asignando el escucha de clics cada vez que se dibuja una vista, ¿verdad?
rgv
1
@Raghav sí, cada vez que se vincula la vista, se asigna un nuevo escucha de clics, pero este es el flujo estándar. Pero mOnItemClickListener se crea solo una vez para el adaptador, solo la vista y su posición son diferentes en cada clic de elemento;)
Sir NIkolay Cesar El primer
3
¡Un gran ejemplo para eliminar el rendimiento de la aplicación y crear un uso excesivo de la memoria! Con este ejemplo, solo necesita desplazarse para crear cientos de objetos inútiles, que en un momento serán inútiles y tendrán que acceder como garbige. @NoobDogg tiene razón. No se deben crear ClickListeners en onBindView. Se debe crear un detector de clics una vez en onCreateView (o el constructor del titular), y existe mientras necesitamos pantalla con este adaptador.
Mykola Tychyna
36

Esto es lo que terminé necesitando, en caso de que alguien lo encuentre útil:

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

    }
}

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

Oveja Fifer
fuente
De todas las versiones que probé, esta es la que tengo trabajando. Pero, ¿está bien hacerlo de esa manera? ¿O hay una mejor manera, como las mejores prácticas?
Matthias Loibl
1
Por lo que pude ver, esta era la única manera. ¡Mira esto para más detalles! stackoverflow.com/a/24933117/1508887
Fifer Sheep
¿Cómo puedo abrir un nuevo fragmento desde dentro del método onclick?
hash
55
getAdapterPosition () reemplaza getPosition ()
Kennedy Nyaga
27

Tengo buena solución para RecyclerView's onItemClickListenerpara los elementos y subelementos

Paso 1- Crea una interfaz

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

Paso 2- Luego úsalo en el onBindViewHoldermétodo del adaptador de la siguiente manera

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

    }

Paso 3- encuentre y configure la vista del reciclador en la actividad o fragmento donde está usando esto

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

Paso 4- Finalmente implemente la interfaz en la actividad o fragmento donde está utilizando la vista de reciclaje

@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
fuente
2
Esta es la mejor solución porque generalmente necesitamos muchas propiedades de actividad / fragmento en nuestro onItemClickListener, y no tiene sentido llamarlo directamente desde el marcador de vista (tendría que crear un constructor personalizado para cada adaptador). Por cierto, su código es un poco extenso, le sugiero que lo corte a la parte más importante (setOnItemClickListener).
sagits
Este es un buen enfoque simple para diferenciar la fila / elemento de los sub-elementos
Nigel Savage
17

Aquí esta lo que hice. Esta solución es compatible con onClick y onLongClick tanto en los elementos RecyclerView como en las vistas internas de los elementos RecyclerView (vistas internas).

Etiqueto viewHolder en las vistas de mi elección:

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

Y utilizo holder.getPosition () para recuperar la posición en el método onClick () (onLongClick es similar):

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

Una variante con getChildPosition también funciona. Tenga en cuenta que para las vistas internas, en onClick () use:

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

En mi opinión, la ventaja de esta solución es que cuando uno hace clic en la imagen, solo se llama al oyente de imágenes onclick (), mientras que cuando combiné la solución de Jacob para una vista de RecyclerView Item y mi solución para vistas internas, la vista de RecyclerView Item onclick ( ) también se llama (cuando se hace clic en la imagen).

u2gilles
fuente
11

Hay una manera mucho más fácil de hacer esto. Simplemente aplique al hacer clic en onBindViewHolderla vista de raíz.

Considere que esta es su vista para el adaptador,

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

Luego haga lo siguiente en su adaptador

//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
fuente
9

Puedes pasar un clickListenera Adapter.

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

luego pásalo a Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

En Adapters 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
fuente
¿Cómo pasas los holdervalores a través de la intención?
RoCk RoCk
8

He desarrollado una biblioteca ligera para Android, puedes visitar https://github.com/ChathuraHettiarachchi/RecycleClick

y siga para la siguiente muestra

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });
Chathura Jayanath
fuente
¡Puedo confirmar que esta biblioteca es genial! Muy fácil de usar, buen trabajo!
peterkodermac
7

Puede implementar OnClickListener en su clase 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());
        }
    }

Y onBindViewHolder establece el elemento del titular de la vista

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }
población
fuente
7

Demasiado simple y efectivo.

En lugar de implementar la interfaz View.OnClickListenerdentro del soporte de vista o crear e interactuar e implementar la interfaz en su actividad, utilicé este código para una OnClickListenerimplementación 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
fuente
3
Esta es una mala práctica común porque parece demasiado fácil. Está creando un nuevo oyente interno cada vez que se vincula un objeto (y cada elemento en un reciclador se puede vincular muchas veces), lo que es malo para a) rendimiento b) recolección de basura. En su lugar, debe crear UN oyente en algún lugar (en el marcador de vista, en el adaptador, en el fragmento o actividad superior) y simplemente agregarlo a los elementos en el constructor del marcador de vista en onCreateViewHolder. Esto tiene la complejidad adicional de tener que averiguar qué elemento fue clicker, pero se puede resolver fácilmente mediante etiquetas o agregando más información al titular.
GuillermoMP
6

Todas las respuestas publicadas hasta el momento son excelentes soluciones, sin embargo, si no desea lidiar con demasiados detalles de implementación y solo desea que funcione de manera similar a como lo hace ListView, recomendaría usar TwoWay-View, como se ve aquí:

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

Tenga en cuenta que esta implementación también admite una presión prolongada sobre los elementos, así como también soporte para estados presionados (que es algo importante que carecen de otras soluciones a esta pregunta).

Si no desea usar toda la biblioteca, eche un vistazo a la clase ClickItemTouchListener , que se puede usar de forma independiente si es necesario. El único problema que encontré en este momento es con una pulsación larga + desplazamiento, parece tener un comportamiento incorrecto.

Jawnnypoo
fuente
6

Si desea capturar el evento de clic en elementos individuales, simplemente implemente OnClickListeneren ViewHolderclase y luego configure los oyentes de clics en vistas individuales o completas itemView.

El siguiente ejemplo muestra lo mismo

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
fuente
5

Para mí, esta es la mejor manera:

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
fuente
3
getChildPosition () es decapitado
Nasz Njoka Sr.
5

El RecyclerViewno tiene un OnClickListenery tendrá que implementarlo nosotros mismos.

Me gusta agregar una OnItemClickListenerinterfaz Adaptercon un onClickmétodo invocado al hacer clic en la vista del elemento desde ViewHolder. Por lo tanto, la responsabilidad de administrar el clic en un elemento está fuera de ViewHoldery Adapter. ¿La actividad o fragmento que decidirá qué hacer?

Agregue una interfaz al oyente y al objeto del oyente.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}

Capturamos el clic de la vista raíz del elemento y cuando se activa la devolución de llamada, se onClickescucha la llamada en el adaptador.

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

Dado que la actividad o fragmento, fragmento en nuestro caso, asignamos un oyente al adaptador y la devolución de llamada onClick obtendremos el elemento seleccionado por posición y abriremos una actividad detallada del elemento.

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
fuente
5

Desafortunadamente, RecyclerViewfaltan un par de características que se ListViewhabían incorporado. Por ejemplo, la capacidad de agregar un elemento OnItemClickListenerque se activa cuando se hace clic en un elemento. RecyclerViewle permite configurar un OnClickListeneren su adaptador, pero pasar ese oyente de clics desde su código de llamada, al adaptador y al ViewHolder, es complicado para detectar un simple clic de elemento.

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

También necesita definir R.id.item_click_supportusando ids.xml:

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

El escucha de clics de código resultante ahora se ve así:

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

Para una breve explicación sobre los clics de la vista de reciclaje, eche un vistazo a este littlerobots_blog

anand krish
fuente
5

puede definir fácilmente setOnClickListener en su clase ViewHolder de la siguiente manera:

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
fuente
5

Esto es lo que hice Leer más y descargar la esencia aquí

Agregando lo mismo aquí

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
fuente
4

Según la mayoría de las respuestas anteriores, parecen estar configurando sus onclicklisteners a elementos individuales. Sin embargo, la solución que voy a ofrecer es muy simple pero no intuitiva para muchos. Muchos se olvidan de que los otros componentes siempre están en un componente principal que se usa para mostrar elementos en las vistas de Lista o Reciclador. Esta solución se trata de configurar un solo oyente onclick para esta vista principal y se juega el turno. La solución también incluye una forma de pasar la posición del elemento en el que se hace clic desde la lista o la vista del reciclador. Aquí, nuestro rootview principal es un CardView de la biblioteca de soporte de Android. Aquí hay un código de muestra

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
fuente
4

Implementación de Kotlin de la respuesta 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
fuente
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();
                }
            });
        }
    }
Excepción de puntero nulo
fuente
3

aquí hay un código completo para mi adaptador personalizado, este código inflará las filas con elementos de lista definidos en el archivo xml llamado "list_item" y también realizará un evento de clic en todas las filas de elementos de lista con sus respectivas posiciones.

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
fuente
2

Podemos hacer esto usando referencias débiles de Java. Semánticamente, el titular de la vista es el que debe responder al evento de clic o delegarlo al respondedor correcto.

Nuestras metas:

  1. Viewholder no debe saber nada acerca de la clase que responde a los eventos, excepto que implementa una interfaz determinada.
  2. El controlador de clics debe obtener la posición en RecyclerView de la vista en la que se hace clic.
  3. Deberíamos poder discernir en qué vista se hizo clic en el titular de la vista.
  4. Mantenga un acoplamiento flojo entre todos los componentes y no provoque ningún ciclo de retención.

Pasos:

  1. Cree una interfaz para manejar respuestas de clic.

  2. Implemente esta interfaz en la Actividad que manejará el clic.

  3. Agregue una variable miembro en el Adaptador RecyclerView para contener la Referencia débil y un constructor que la establezca.

  4. Haga lo mismo en RecyclerView ViewHolder y agregue una variable miembro para realizar un seguimiento de la posición.

  5. Establezca sus oyentes de clic en cualquier vista que desee en ViewHolder, luego vuelva a llamar al respondedor para manejarlos.

  6. Cambie su método onBindViewHolder para establecer la posición al vincular.

  7. Pase el respondedor al ViewHolder.

  8. En el respondedor, ahora puede usar getId () en la vista para averiguar en qué vista se hizo clic.

Y aquí hay un resumen para que pueda ver cómo encaja todo: manejo de clics de RecyclerView

Rajiev Timal
fuente
2

Soy consciente de que hay muchas respuestas, pero pensé que podría proporcionar mi implementación también. (Los detalles completos se pueden encontrar en otra pregunta que respondí ).

Entonces, para agregar un escucha de clics, su ViewHolderclase interna necesita implementarse View.OnClickListener. Esto se debe a que va a configurar una OnClickListeneral itemViewparámetro del ViewHolderconstructor 's. Déjame mostrarte lo que quiero decir:

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

Las únicas otras cosas que necesita agregar son una interfaz personalizada para usted Adaptery un método de establecimiento:

private OnEntryClickListener mOnEntryClickListener;

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

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

Entonces su nuevo soporte de clics Adapterestá completo.

Ahora, usémoslo ...

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

Básicamente, es cómo configurar un normal Adapter, excepto que usa el método de establecimiento que creó para controlar lo que hará cuando su usuario haga clic en un elemento de la lista en particular.

También puede ver un conjunto de ejemplos que hice en este Gist en GitHub:

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

Farbod Salamat-Zadeh
fuente
Debería usar getAdapterPosition () en lugar de getLayoutPosition ()
BladeCoder
2

Esto es lo que hago para reutilizar OnClickListener

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

en ViewHoder Tome el elemento primario de itemlayout

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

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

en onBindViewHolder establece la etiqueta como posición

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

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

y en 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
fuente
2

Para mí, la forma limpia de hacerlo es esta.

Constructor adaptador

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

La interfaz vinculada

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
Jeremie Petitjean
fuente