recyclerview item from for java android android-recyclerview

java - from - ¿Por qué RecyclerView no tiene onItemClickListener()?



recyclerview clickable items (30)

funciono para mi Espero que ayude. La forma más sencilla.

Titular de vista interior

class GeneralViewHolder extends RecyclerView.ViewHolder { View cachedView = null; public GeneralViewHolder(View itemView) { super(itemView); cachedView = itemView; }

Dentro de OnBindViewHolder ()

@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder; generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show(); } });

Y hágamelo saber, ¿tiene alguna pregunta sobre esta solución?

Estaba explorando RecyclerView y me sorprendió ver que RecyclerView no tiene onItemClickListener() . Porque RecyclerView extiende

android.view.ViewGroup

y ListView extiende

android.widget.AbsListView

. Sin embargo, resolví mi problema escribiendo onClick en mi RecyclerView.Adapter :

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener { public TextView txtViewTitle; public ImageView imgViewIcon; public ViewHolder(View itemLayoutView) { super(itemLayoutView); txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title); imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon); } @Override public void onClick(View v) { } }

Pero todavía quiero saber por qué Google eliminó onItemClickListener() ?

¿Hay un problema de rendimiento o algo más?


Android Recyclerview Con onItemClickListener , ¿Por qué no podemos intentarlo? Esto funciona solo como ListView .

Fuente: Link

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { public void onItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } }); } @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) { } }

Y configúralo en RecyclerView:

recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.addOnItemTouchListener( new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { // TODO Handle item click Log.e("@@@@@",""+position); } }) );


Cómo ponerlo todo junto ejemplo ...

  • Manejo onClick ()
  • Cursor - RecyclerView
  • Tipos de ViewHolder

    public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> { private static final String TAG = OrderListCursorAdapter.class.getSimpleName(); private static final int ID_VIEW_HOLDER_ACTUAL = 0; private static final int ID_VIEW_HOLDER = 1; public OrderListCursorAdapter(Context context, Cursor cursor) { super(context, cursor); } public static class ViewHolderActual extends ViewHolder { private static final String TAG = ViewHolderActual.class.getSimpleName(); protected IViewHolderClick listener; protected Button button; public ViewHolderActual(View v, IViewHolderClick listener) { super(v, listener); this.listener = listener; button = (Button) v.findViewById(R.id.orderList_item_button); button.setOnClickListener(this); } public void initFromData(OrderData data) { Log.d(TAG, "><initFromData(data=" + data + ")"); orderId = data.getId(); vAddressStart.setText(data.getAddressStart()); vAddressEnd.setText(data.getAddressEnd()); } @Override public void onClick(View view) { if (view instanceof Button) { listener.onButtonClick((Button) view, getPosition(), this); } else { super.onClick(view); } } public interface IViewHolderClick extends ViewHolder.IViewHolderClick { public void onButtonClick(Button button, int position, ViewHolder viewHolder); } } public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private static final String TAG = ViewHolder.class.getSimpleName(); protected long orderId; protected IViewHolderClick listener; protected TextView vAddressStart; protected TextView vAddressEnd; protected TextView vStatus; public ViewHolder(View v, IViewHolderClick listener) { super(v); this.listener = listener; v.setOnClickListener(this); vAddressStart = (TextView) v.findViewById(R.id.addressStart); vAddressEnd = (TextView) v.findViewById(R.id.addressEnd); vStatus = (TextView) v.findViewById(R.id.status); } public void initFromData(OrderData data) { Log.d(TAG, "><initFromData(data=" + data + ")"); orderId = data.getId(); vAddressStart.setText(data.getAddressStart()); vAddressEnd.setText(data.getAddressEnd()); } public long getOrderId() { return orderId; } @Override public void onClick(View view) { listener.onCardClick(view, getPosition(), this); } public interface IViewHolderClick { public void onCardClick(View view, int position, ViewHolder viewHolder); } } @Override public int getItemViewType(int position) { return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")"); ViewHolder result; switch (viewType) { case ID_VIEW_HOLDER_ACTUAL: { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false); result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() { @Override public void onCardClick(View view, int position, ViewHolder viewHolder) { Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")"); Intent intent = new Intent(view.getContext(), OrderDetailActivity.class); intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId()); view.getContext().startActivity(intent); } @Override public void onButtonClick(Button button, int position, ViewHolder viewHolder) { Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")"); Intent intent = new Intent(button.getContext(), OrderMapActivity.class); intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId()); button.getContext().startActivity(intent); } }); break; } case ID_VIEW_HOLDER: default: { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false); result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() { @Override public void onCardClick(View view, int position, ViewHolder viewHolder) { Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")"); Intent intent = new Intent(view.getContext(), OrderDetailActivity.class); intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId()); view.getContext().startActivity(intent); } }); break; } } Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result); return result; } @Override public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) { Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")"); final OrderData orderData = new OrderData(cursor); viewHolder.initFromData(orderData); } }


Chicos usan este código en tu actividad principal. Método muy eficiente

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list); UsersAdapter adapter = new UsersAdapter(users, this); recyclerView.setAdapter(adapter); adapter.setOnCardClickListner(this);

Aquí está su clase de adaptador.

public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> { private ArrayList<User> mDataSet; OnCardClickListner onCardClickListner; public UsersAdapter(ArrayList<User> mDataSet) { this.mDataSet = mDataSet; } @Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false); UserViewHolder userViewHolder = new UserViewHolder(v); return userViewHolder; } @Override public void onBindViewHolder(UserViewHolder holder, final int position) { holder.name_entry.setText(mDataSet.get(position).getUser_name()); holder.cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onCardClickListner.OnCardClicked(v, position); } }); } @Override public int getItemCount() { return mDataSet.size(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } public static class UserViewHolder extends RecyclerView.ViewHolder { CardView cardView; TextView name_entry; public UserViewHolder(View itemView) { super(itemView); cardView = (CardView) itemView.findViewById(R.id.user_layout); name_entry = (TextView) itemView.findViewById(R.id.name_entry); } } public interface OnCardClickListner { void OnCardClicked(View view, int position); } public void setOnCardClickListner(OnCardClickListner onCardClickListner) { this.onCardClickListner = onCardClickListner; } }

Después de esto, obtendrá este método de anulación en su actividad.

@Override public void OnCardClicked(View view, int position) { Log.d("OnClick", "Card Position" + position); }


Después de leer la respuesta de @ MLProgrammer-CiM , aquí está mi código:

class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ @Bind(R.id.card_item_normal) CardView cardView; public NormalViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); cardView.setOnClickListener(this); } @Override public void onClick(View v) { if(v instanceof CardView) { // use getAdapterPosition() instead of getLayoutPosition() int itemPosition = getAdapterPosition(); removeItem(itemPosition); } } }


Esta es una forma de implementarlo fácilmente si tiene una lista de POJO y desea recuperar uno al hacer clic desde fuera del adaptador.

En su adaptador, cree una escucha para los eventos de clic y un método para configurarlo:

public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> { ... private List<MyPojo> mMyPojos; private static OnItemClickListener mOnItemClickListener; ... public interface OnItemClickListener { public void onItemClick(MyPojo pojo); } ... public void setOnItemClickListener(OnItemClickListener onItemClickListener){ mOnItemClickListener = onItemClickListener; } ...

}

In your ViewHolder, implement onClickListener and create a class member to temporarily store the POJO the view is presenting, that way (this is an example, creating a setter would be better):

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public MyPojo mCurrentPojo; ... public ViewHolder(View view) { super(v); ... view.setOnClickListener(this); //You could set this on part of the layout too } ... @Override public void onClick(View view) { if(mOnItemClickListener != null && mCurrentPojo != null){ mOnItemClickListener.onItemClick(mCurrentPojo); } }

Back in your adapter, set the current POJO when the ViewHolder is bound (or to null if the current view doesn''t have one):

@Override public void onBindViewHolder(final ViewHolder holder, final int position) { final MyPojo currentPojo = mMyPojos.get(position); holder.mCurrentPojo = currentPojo; ...

That''s it, now you can use it like this from your fragment/activity:

mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() { @Override public void onItemClick(MyPojo pojo) { //Do whatever you want with your pojo here } });


Esto funcionó para mí:

@Override public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) { ---- ---- ---- // Set setOnClickListener(holder); } @Override public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { ---- ---- ---- @Override public void onClick(View view) { // Use to get the item clicked getAdapterPosition() } }


Gracias a @marmor, actualicé mi respuesta.

Creo que es una buena solución para manejar el onClick () en el constructor de la clase ViewHolder y pasarlo a la clase principal a través de la interfaz OnItemClickListener .

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{ private LayoutInflater layoutInflater; private List<MyObject> items; private AdapterView.OnItemClickListener onItemClickListener; public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) { layoutInflater = LayoutInflater.from(context); this.items = items; this.onItemClickListener = onItemClickListener; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { MyObject item = items.get(position); } public MyObject getItem(int position) { return items.get(position); } class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView title; private ImageView avatar; public ViewHolder(View itemView) { super(itemView); title = itemView.findViewById(R.id.title); avatar = itemView.findViewById(R.id.avatar); title.setOnClickListener(this); avatar.setOnClickListener(this); itemView.setOnClickListener(this); } @Override public void onClick(View view) { //passing the clicked position to the parent class onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId()); } } }

Uso del adaptador en otras clases:

MyFragment.java

public class MyFragment extends Fragment implements AdapterView.OnItemClickListener { private RecyclerView recycleview; private MyAdapter adapter; . . . private void init(Context context) { //passing this fragment as OnItemClickListener to the adapter adapter = new MyAdapter(context, this, items); recycleview.setAdapter(adapter); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //you can get the clicked item from the adapter using its position MyObject item = adapter.getItem(position); //you can also find out which view was clicked switch (view.getId()) { case R.id.title: //title view was clicked break; case R.id.avatar: //avatar view was clicked break; default: //the whole row was clicked } } }


He hecho esto, es muy simple:

Solo agregue 1 línea para la posición RecyclerView pulsada :

int position = getLayoutPosition()

Código completo para la clase ViewHolder :

private class ChildViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public TextView txtView; public ChildViewHolder(View itemView) { super(itemView); imageView= (ImageView)itemView.findViewById(R.id.imageView); txtView= (TextView) itemView.findViewById(R.id.txtView); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition())); } }); } }

Espero que esto te ayudará.


Me gusta así y lo estoy usando.

Dentro

public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

Poner

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false); v.setOnClickListener(new MyOnClickListener());

Y crea esta clase donde quieras.

class MyOnClickListener implements View.OnClickListener { @Override public void onClick(View v) { int itemPosition = recyclerView.indexOfChild(v); Log.e("Clicked and Position is ",String.valueOf(itemPosition)); } }

He leído antes que hay una mejor manera, pero me gusta de esta manera es fácil y no es complicado.


Por lo que entiendo de la respuesta de MLProgrammer-CiM , simplemente es posible hacer esto:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private ImageView image; private TextView title; private TextView price; public MyViewHolder(View itemView) { super(itemView); image = (ImageView)itemView.findViewById(R.id.horizontal_list_image); title = (TextView)itemView.findViewById(R.id.horizontal_list_title); price = (TextView)itemView.findViewById(R.id.horizontal_list_price); image.setOnClickListener(this); title.setOnClickListener(this); price.setOnClickListener(this); } @Override public void onClick(View v) { Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show(); } }


Siguiendo la excelente solución RxJava de MLProgrammer-CiM

Consumir / Observar clics

ReactiveAdapter rxAdapter = new ReactiveAdapter(); rxAdapter.getPositionClicks().subscribe(mClickConsumer); Consumer<String> mClickConsumer = new Consumer<String>() { @Override public void accept(@NonNull String element) throws Exception { Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show(); } };

RxJava 2. +

Modificar el tl; dr original como:

public Observable<String> getPositionClicks(){ return onClickSubject; }

PublishSubject#asObservable() fue eliminado. Solo devuelve el PublishSubject que es un Observable .


Una solución alternativa es la proposed por Hugo Visser , un GDE de Android. Hizo una clase sin licencia disponible para que solo ingreses tu código y lo uses.

Uso:

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

(También soporta el clic de elemento largo)

Implementación (comentarios agregados por mi):

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) { // ask the RecyclerView for the viewHolder of this view. // then use it to get the position for the adapter 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) { // every time a new child view is attached add click listeners to it if (mOnItemClickListener != null) { view.setOnClickListener(mOnClickListener); } if (mOnItemLongClickListener != null) { view.setOnLongClickListener(mOnLongClickListener); } } @Override public void onChildViewDetachedFromWindow(View view) { } }; private ItemClickSupport(RecyclerView recyclerView) { mRecyclerView = recyclerView; // the ID must be declared in XML, used to avoid // replacing the ItemClickSupport without removing // the old one from the RecyclerView mRecyclerView.setTag(R.id.item_click_support, this); mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener); } public static ItemClickSupport addTo(RecyclerView view) { // if there''s already an ItemClickSupport attached // to this RecyclerView do not replace it, use it 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 cree un archivo de values/ids.xml y ponga esto en él:

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

Esta clase funciona adjuntando un RecyclerView.OnChildAttachStateChangeListener al RecyclerView . Este oyente recibe una notificación cada vez que un niño se adjunta o se separa de RecyclerView . El código lo utiliza para añadir un escuchador de pulsación / clic largo a la vista. Ese oyente pregunta a RecyclerView para RecyclerView.ViewHolder que contiene la posición.

También puede adaptar el código para devolverle el soporte si necesita más.

Tenga en cuenta que está COMPLETAMENTE bien manejarlo en su adaptador estableciendo en cada vista de su lista un detector de clics, como otra respuesta propuesta. Simplemente no es lo más eficiente (crea un nuevo oyente cada vez que reutiliza una vista) pero funciona y en la mayoría de los casos no es un problema.

Acerca del Por qué RecyclerView no tiene un onItemClickListener .

RecyclerView es una caja de herramientas, en contraste con el viejo ListView , tiene menos funciones integradas y más flexibilidad. onItemClickListener no es la única función que se elimina de ListView. Pero tiene muchos oyentes y un método para extenderlo a su gusto, es mucho más poderoso en las manos adecuadas;).

En mi opinión, la característica más compleja eliminada en RecyclerView es el desplazamiento rápido . La mayoría de las otras características se pueden volver a implementar fácilmente.


Utilizo este método para iniciar una Intención desde RecyclerView:

@Override public void onBindViewHolder(ViewHolder viewHolder, int i) { final MyClass myClass = mList.get(i); viewHolder.txtViewTitle.setText(myclass.name); ... viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v){ Intent detailIntent = new Intent(mContext, type.class); detailIntent.putExtra("MyClass", myclass); mContext.startActivity(detailIntent); } } );


> ¿En qué se diferencia RecyclerView de Listview?

Una diferencia es que existe LayoutManager clase LayoutManager con RecyclerView por la cual puede administrar su RecyclerView :

Desplazamiento horizontal o vertical por LinearLayoutManager

GridLayout por GridLayoutManager

Staggered GridLayout por StaggeredGridLayoutManager

Al igual que para el desplazamiento horizontal para RecyclerView-

LinearLayoutManager llm = new LinearLayoutManager(context); llm.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(llm);


tl; dr 2016 Use RxJava y PublishSubject para exponer un Observable para los clics.

public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { String[] mDataset = { "Data", "In", "Adapter" }; private final PublishSubject<String> onClickSubject = PublishSubject.create(); @Override public void onBindViewHolder(final ViewHolder holder, int position) { final String element = mDataset[position]; holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onClickSubject.onNext(element); } }); } public Observable<String> getPositionClicks(){ return onClickSubject.asObservable(); } }

Mensaje original:

Desde la introducción de ListView , onItemClickListener ha sido problemático. En el momento en que tiene un detector de clics para cualquiera de los elementos internos, la devolución de llamada no se activaría, pero no fue notificada o bien documentada (en todo caso), por lo que hubo mucha confusión y SO preguntas al respecto.

Dado que RecyclerView lleva un paso más allá y no tiene un concepto de fila / columna, sino más bien una cantidad de hijos dispuesta arbitrariamente, han delegado el onClick en cada uno de ellos o en la implementación del programador.

Piense en Recyclerview no como un reemplazo ListView 1: 1 sino como un componente más flexible para casos de uso complejos. Y como dices, tu solución es lo que Google esperaba de ti. Ahora tiene un adaptador que puede delegar onClick en una interfaz pasada en el constructor, que es el patrón correcto para ListView y Recyclerview .

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener { public TextView txtViewTitle; public ImageView imgViewIcon; public IMyViewHolderClicks mListener; public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) { super(itemLayoutView); mListener = listener; txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title); imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon); imgViewIcon.setOnClickListener(this); itemLayoutView.setOnClickListener(this); } @Override public void onClick(View v) { if (v instanceof ImageView){ mListener.onTomato((ImageView)v); } else { mListener.onPotato(v); } } public static interface IMyViewHolderClicks { public void onPotato(View caller); public void onTomato(ImageView callerImage); } }

y luego en su adaptador

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { String[] mDataset = { "Data" }; @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false); MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() { public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); }; public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); } }); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { // Get element from your dataset at this position // Replace the contents of the view with that element // Clear the ones that won''t be used holder.txtViewTitle.setText(mDataset[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } ...

Ahora mire el último fragmento de código: onCreateViewHolder(ViewGroup parent, int viewType) la firma ya sugiere diferentes tipos de vista. Para cada uno de ellos también necesitará un visor diferente, y posteriormente cada uno de ellos puede tener un conjunto diferente de clics. O simplemente puede crear un punto de vista genérico que tome cualquier vista y otro onClickListener y se aplique en consecuencia. O delegue un nivel al orquestador para que varios fragmentos / actividades tengan la misma lista con diferentes comportamientos de clic. Una vez más, toda la flexibilidad está de su lado.

Es un componente realmente necesario y bastante cercano a lo que eran hasta ahora nuestras implementaciones internas y mejoras a ListView . Es bueno que Google finalmente lo reconozca.


Aquí puede manejar varios códigos onclick ver más abajo y es muy eficiente

public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> { private Context context; List<News> newsList; // Allows to remember the last item shown on screen private int lastPosition = -1; public RVNewsAdapter(List<News> newsList, Context context) { this.newsList = newsList; this.context = context; } public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener { ImageView img_main; TextView tv_title; Button bt_facebook, bt_twitter, bt_share, bt_comment; public FeedHolder(View itemView) { super(itemView); img_main = (ImageView) itemView.findViewById(R.id.img_main); tv_title = (TextView) itemView.findViewById(R.id.tv_title); bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook); bt_twitter = (Button) itemView.findViewById(R.id.bt_twitter); bt_share = (Button) itemView.findViewById(R.id.bt_share); bt_comment = (Button) itemView.findViewById(R.id.bt_comment); img_main.setOnClickListener(this); bt_facebook.setOnClickListener(this); bt_twitter.setOnClickListener(this); bt_comment.setOnClickListener(this); bt_share.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == bt_comment.getId()) { Toast.makeText(v.getContext(), "Comment " , Toast.LENGTH_SHORT).show(); } else if (v.getId() == bt_facebook.getId()) { Toast.makeText(v.getContext(), "Facebook " , Toast.LENGTH_SHORT).show(); } else if (v.getId() == bt_twitter.getId()) { Toast.makeText(v.getContext(), "Twitter " , Toast.LENGTH_SHORT).show(); } else if (v.getId() == bt_share.getId()) { Toast.makeText(v.getContext(), "share " , Toast.LENGTH_SHORT).show(); } else { Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show(); } } } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } @Override public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false); FeedHolder feedHolder = new FeedHolder(view); return feedHolder; } @Override public void onBindViewHolder(FeedHolder holder, int position) { holder.tv_title.setText(newsList.get(position).getTitle()); // Here you apply the animation when the view is bound setAnimation(holder.img_main, position); } @Override public int getItemCount() { return newsList.size(); } /** * Here is the key method to apply the animation */ private void setAnimation(View viewToAnimate, int position) { // If the bound view wasn''t previously displayed on screen, it''s animated if (position > lastPosition) { Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left); viewToAnimate.startAnimation(animation); lastPosition = position; } } }


En lugar de implementar la interfaz View.OnClickListener dentro del titular de la vista o crear e interconectar e implementar la interfaz en su actividad ... Utilicé este código para simplificar la implementación de OnClickListener.

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


If you want to add onClick() to the child view of items, for example, a button in item, I found that you can do it easily in onCreateViewHolder() of your own RecyclerView.Adapter just like this:

@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater .from(parent.getContext()) .inflate(R.layout.cell, null); Button btn = (Button) v.findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do it } }); return new MyViewHolder(v); }

i don''t know whether it''s a good way, but it works well. If anyone has a better idea, very glad to tell me and correct my answer! :)


Marque este en el que he implementado todas las cosas de manera adecuada.

RecyclerViewHolder Class

public class RecyclerViewHolder extends RecyclerView.ViewHolder { //view holder is for girdview as we used in the listView public ImageView imageView,imageView2; public RecyclerViewHolder(View itemView) { super(itemView); this.imageView=(ImageView)itemView.findViewById(R.id.image); } }

Adaptador

public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> { //RecyclerView will extend to recayclerview Adapter private ArrayList<ModelClass> arrayList; private Context context; private static RecyclerViewClickListener itemListener; //constructor of the RecyclerView Adapter RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){ this.context=context; this.arrayList=arrayList; this.itemListener=itemListener; } @Override public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //this method will inflate the custom layout and return as viewHolder LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext()); ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false); RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup); return listHolder; } @Override public void onBindViewHolder(RecyclerViewHolder holder, final int position) { final ModelClass modelClass=arrayList.get(position); //holder RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder; //convert the drawable image into bitmap Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage()); //set the image into imageView mainHolder.imageView.setImageBitmap(image); //to handle on click event when clicked on the recyclerview item and // get it through the RecyclerViewHolder class we have defined the views there mainHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //get the position of the image which is clicked itemListener.recyclerViewListClicked(v,position); } }); } @Override public int getItemCount() { return (null!=arrayList?arrayList.size():0); } }

La interfaz

public interface RecyclerViewClickListener { //this is method to handle the event when clicked on the image in Recyclerview public void recyclerViewListClicked(View v,int position); } //and to call this method in activity RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this); recyclerView.setAdapter(adapter); adapter.notifyDataSetChanged(); @Override public void recyclerViewListClicked(View v,int position){ imageView.setImageResource(wallpaperImages[position]); }


Me gusta así y lo estoy usando.

Dentro

public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

Poner

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false); v.setOnClickListener(new MyOnClickListener());

Y crea esta clase donde quieras.

class MyOnClickListener implements View.OnClickListener { @Override public void onClick(View v) { int itemPosition = recyclerView.indexOfChild(v); Log.e("Clicked and Position is ",String.valueOf(itemPosition)); } }

He leído antes que hay una mejor manera, pero me gusta de esta manera es fácil y no es complicado. Espero que te ayude ..!


Modifiqué mi comentario ...

public class MyViewHolder extends RecyclerView.ViewHolder { private Context mContext; public MyViewHolder(View itemView) { super(itemView); mContext = itemView.getContext(); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int itemPosition = getLayoutPosition(); Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show(); } }); }


See my approach on this:

First declare an interface like this:

/** * Interface used for delegating item click events in a {@link android.support.v7.widget.RecyclerView} * Created by Alex on 11/28/2015. */ public interface OnRecyclerItemClickListener<T> { /** * Called when a click occurred inside a recyclerView item view * @param view that was clicked * @param position of the clicked view * @param item the concrete data that is displayed through the clicked view */ void onItemClick(View view, int position, T item); }

Then create the adapter:

public class CustomRecyclerAdapter extends RecyclerView.Adapter { private class InternalClickListener implements View.OnClickListener{ @Override public void onClick(View v) { if(mRecyclerView != null && mItemClickListener != null){ // find the position of the item that was clicked int position = mRecyclerView.getChildAdapterPosition(v); Data data = getItem(position); // notify the main listener mItemClickListener.onItemClick(v, position, data); } } } private final OnRecyclerItemClickListener mItemClickListener; private RecyclerView mRecyclerView; private InternalClickListener mInternalClickListener; /** * * @param itemClickListener used to trigger an item click event */ public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){ mItemClickListener = itemClickListener; mInternalClickListener = new InternalClickListener(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false); v.setOnClickListener(mInternalClickListener); ViewHolder viewHolder = new ViewHolder(v); return viewHolder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { // do your binding here } @Override public int getItemCount() { return mDataSet.size(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView = recyclerView; } @Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); mRecyclerView = null; } public Data getItem(int position){ return mDataset.get(position); } }

And now let''s see how to integrate this from a fragment:

public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{ private RecyclerView mRecyclerView; @Override public void onItemClick(View view, int position, Data item) { // do something } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.test_fragment, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { mRecyclerView = view.findViewById(idOfTheRecycler); mRecyclerView .setAdapter(new CustomRecyclerAdapter(this)); }


sí tu puedes

public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) { //inflate the view View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null); ViewHolder holder = new ViewHolder(view); //here we can set onClicklistener view.setOnClickListener(new View.OnClickListeener(){ public void onClick(View v) { //action } }); return holder;


Acceder a la mainViewde rowLayout(cell)para usted RecyclerViewy en su OnBindViewHolderescritura este código:

@Override public void onBindViewHolder(MyViewHolder holder, final int position) { Movie movie = moviesList.get(position); holder.mainView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { System.out.println("pos " + position); } }); }


Escribí una biblioteca para manejar el evento de clic del elemento de la vista del reciclador de Android. Puede encontrar un tutorial completo en https://github.com/ChathuraHettiarachchi/RecycleClick

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { // YOUR CODE } });

o para manejar el artículo de prensa larga puede utilizar

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() { @Override public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) { // YOUR CODE return true; } });


La animación de Recyclerview no ha sido probada, la otra es normal. Creo que se ha optimizado al máximo. La interfaz tiene otros usos, puedes ignorar temporalmente.

public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface { public final String TAG = getClass().getSimpleName(); protected final Activity mActivity; protected final LayoutInflater mInflater; protected ItemClickInterface<?, Integer> mListener; public BaseAdapterRV(Activity activity) { mActivity = activity; mInflater = LayoutInflater.from(mActivity); } @Override public final VH onCreateViewHolder(ViewGroup parent, int viewType) { return onCreateViewHolder(parent, viewType, mInflater); } @Override public final void onBindViewHolder(VH holder, int position) { holder.itemView.setTag(R.id.tag_view_click, position); //创建点击事件 holder.itemView.setOnClickListener(mListener); holder.itemView.setOnLongClickListener(mListener); onBindVH(holder, position); } /////////////////////////////////////////////////////////////////////////// // 以下是增加的方法 /////////////////////////////////////////////////////////////////////////// /** * 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确 * 里面也有onItemLongClick */ public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) { mListener = listener; notifyDataSetChanged(); } @NonNull protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater); protected abstract void onBindVH(VH holder, int position); }

Esto es interfaz

/** * OnItemClickListener的接口 * 见子类实现{@link OnItemClickListener}{@link OnItemItemClickListener} */ public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener { void onItemClick(DATA1 data1, DATA2 data2); boolean onItemLongClick(DATA1 data1, DATA2 data2); }

Esto es una clase abstracta

public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> { @Override public void onClick(View v) { onItemClick(v, (DATA) v.getTag(R.id.tag_view_click)); } @Override public boolean onLongClick(View v) { return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click)); } @Override public boolean onItemLongClick(View view, DATA data) { return false; } }

Solo lo necesitas

mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() { @Override public void onItemClick(View view, Integer integer) { } @Override public boolean onItemLongClick(View view, Integer integer) { return true; } });


RecyclerView no tiene una onItemClickListenerporque RecyclerView es responsable de reciclar las vistas (¡sorpresa!), Por lo que es responsabilidad de la vista que se recicla para manejar los eventos de clic que recibe.

En realidad, esto lo hace mucho más fácil de usar, especialmente si tenía elementos en los que se puede hacer clic en varios lugares.

De todos modos, detectar el clic en un elemento RecyclerView es muy fácil. Todo lo que necesitas hacer es definir una interfaz (si no estás usando Kotlin, en cuyo caso simplemente pasas una lambda):

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { private final Clicks clicks; public MyAdapter(Clicks clicks) { this.clicks = clicks; } private List<MyObject> items = Collections.emptyList(); public void updateData(List<MyObject> items) { this.items = items; notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations } public interface Clicks { void onItemSelected(MyObject myObject, int position); } public class MyViewHolder extends RecyclerView.ViewHolder { private MyObject myObject; public MyViewHolder(View view) { super(view); // bind views view.setOnClickListener((v) -> { int adapterPosition = getAdapterPosition(); if(adapterPosition >= 0) { clicks.onItemSelected(myObject, adapterPosition); } }); } public void bind(MyObject myObject) { this.myObject = myObject; // bind data to views } } }

Mismo código en Kotlin:

class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() { private var items: List<MyObject> = Collections.emptyList() fun updateData(items: List<MyObject>) { this.items = items notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations } inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) { private lateinit var myObject: MyObject init { // binds views myView.onClick { val adapterPosition = getAdapterPosition() if(adapterPosition >= 0) { itemClicks.invoke(myObject, adapterPosition) } } } fun bind(myObject: MyObject) { this.myObject = myObject // bind data to views } } }


utilizar PlaceHolderView

@Layout(R.layout.item_view_1) public class View1{ @View(R.id.txt) public TextView txt; @Resolve public void onResolved() { txt.setText(String.valueOf(System.currentTimeMillis() / 1000)); } @Click(R.id.btn) public void onClick(){ txt.setText(String.valueOf(System.currentTimeMillis() / 1000)); } }


main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY())); switch (position) { case 0: { wifi(position); adapter2.notifyDataSetChanged(); } break; case 1: { sound(position); adapter2.notifyDataSetChanged(); } break; case 2: { bluetooth(position); adapter2.notifyDataSetChanged(); } break; } return true; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } });