studio seleccionar recyclerview item eventos eliminar elemento ejemplo adaptador android android-support-library android-recyclerview android-cardview

android - seleccionar - ¿Cómo consigo la posición seleccionada en un RecyclerView?



recyclerview seleccionar item (11)

Estoy experimentando con el recyclerview y las tarjetas de la biblioteca de soporte. Tengo un recyclerview de tarjetas. Cada tarjeta tiene un icono ''x'' en la esquina superior derecha para eliminarla:

La tarjeta xml, list_item.xml :

<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/taskDesc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:textSize="40sp" android:text="hi"/> <ImageView android:id="@+id/xImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:src="@drawable/ic_remove"/> </RelativeLayout> </android.support.v7.widget.CardView>

notifyItemRemoved(position) etiquetar la fila con la posición que usaría en notifyItemRemoved(position) en TaskAdapter.java :

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder> { private List<Task> taskList; private TaskAdapter thisAdapter = this; // cache of views to reduce number of findViewById calls public static class TaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { protected TextView taskTV; protected ImageView closeBtn; public TaskViewHolder(View v) { super(v); taskTV = (TextView)v.findViewById(R.id.taskDesc); } @Override public void onClick(View v) { int position = v.getTag(); adapter.notifyItemRemoved(position); } } public TaskAdapter(List<Task> tasks) { if(tasks == null) throw new IllegalArgumentException("tasks cannot be null"); taskList = tasks; } // onBindViewHolder binds a model to a viewholder @Override public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) { final int position = pos; Task currTask = taskList.get(pos); taskViewHolder.taskTV.setText(currTask.getDescription()); taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { thisAdapter.notifyItemRemoved(position); } }); } @Override public int getItemCount() { return taskList.size(); } // inflates row to create a viewHolder @Override public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos) { View itemView = LayoutInflater.from(parent.getContext()). inflate(R.layout.list_item, parent, false); return new TaskViewHolder(itemView); } }

Esto no funcionará porque no puede establecer una etiqueta ni puedo acceder al adaptador desde onClick.


Configure sus onClickListener s en onBindViewHolder() y podrá acceder a la posición desde allí. Si los configura en su ViewHolder , no sabrá en qué posición se hizo clic a menos que también pase la posición al ViewHolder

EDITAR

Como pskink señaló, ViewHolder tiene un getPosition() por lo que la forma en que lo estaba haciendo originalmente era correcta.

Cuando se hace clic en la vista, puede usar getPosition() en su ViewHolder y retorna la posición

Actualizar

getPosition() ahora está en desuso y reemplazado con getAdapterPosition()


Creo que la forma más correcta de obtener la posición del elemento es

View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { View view = v; View parent = (View) v.getParent(); while (!(parent instanceof RecyclerView)){ view=parent; parent = (View) parent.getParent(); } int position = recyclerView.getChildAdapterPosition(view); }

Debido a la vista, no siempre haces clic en la vista raíz del diseño de tu fila. Si la vista no es una raíz (por ejemplo, botones), obtendrá la excepción de conversión de clase. Por lo tanto, al principio debemos encontrar la vista, que es un elemento directo de su consulta. Luego, encuentre la posición usando recyclerView.getChildAdapterPosition (ver);


Enfócate niño, y úsalo para posicionarte en el adaptador.

mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())


No es necesario tener su ViewHolder implementando View.OnClickListener. Puede obtener directamente la posición en la que se hizo clic configurando un detector de clics en el método onCreateViewHolder of RecyclerView.Adapter aquí es una muestra del código:

public class ItemListAdapterRecycler extends RecyclerView.Adapter<ItemViewHolder> { private final List<Item> items; public ItemListAdapterRecycler(List<Item> items) { this.items = items; } @Override public ItemViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int currentPosition = getClickedPosition(view); Log.d("DEBUG", "" + currentPosition); } }); return new ItemViewHolder(view); } @Override public void onBindViewHolder(ItemViewHolder itemViewHolder, int position) { ... } @Override public int getItemCount() { return items.size(); } private int getClickedPosition(View clickedView) { RecyclerView recyclerView = (RecyclerView) clickedView.getParent(); ItemViewHolder currentViewHolder = (ItemViewHolder) recyclerView.getChildViewHolder(clickedView); return currentViewHolder.getAdapterPosition(); } }


Para complementar la respuesta de @tyczj:

Adaptador genérico de código pseido:

public abstract class GenericRecycleAdapter<T, K extends RecyclerView.ViewHolder> extends RecyclerView.Adapter{ private List<T> mList; //default implementation code public abstract int getLayout(); @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(getLayout(), parent, false); return getCustomHolder(v); } public Holders.TextImageHolder getCustomHolder(View v) { return new Holders.TextImageHolder(v){ @Override public void onClick(View v) { onItem(mList.get(this.getAdapterPosition())); } }; } abstract void onItem(T t); @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { onSet(mList.get(position), (K) holder); } public abstract void onSet(T item, K holder); }

ViewHolder:

public class Holders { public static class TextImageHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ public TextView text; public TextImageHolder(View itemView) { super(itemView); text = (TextView) itemView.findViewById(R.id.text); text.setOnClickListener(this); } @Override public void onClick(View v) { } } }

Uso del adaptador:

public class CategoriesAdapter extends GenericRecycleAdapter<Category, Holders.TextImageHolder> { public CategoriesAdapter(List<Category> list, Context context) { super(list, context); } @Override void onItem(Category category) { } @Override public int getLayout() { return R.layout.categories_row; } @Override public void onSet(Category item, Holders.TextImageHolder holder) { } }


Personalmente, la forma más sencilla que he encontrado y funciona bien para mí es la siguiente:

Cree una interfaz dentro de su clase "RecycleAdapter" (Subclase)

public interface ClickCallback { void onItemClick(int position); }

Agregue una variable de la interfaz como un parámetro en el Constructor.

private String[] items; private ClickCallback callback; public RecyclerAdapter(String[] items, ClickCallback clickCallback) { this.items = items; this.callback = clickCallback; }

Establezca un detector de clics en ViewHolder (otra subclase) y pase la ''posición'' a través de la interfaz

AwesomeViewHolder(View itemView) { super(itemView); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { callback.onItemClick(getAdapterPosition()); } }); mTextView = (TextView) itemView.findViewById(R.id.mTextView); }

Ahora, al inicializar el adaptador de reciclador en una actividad / fragmento, simplemente cree un nuevo ''ClickCallback'' (interfaz)

String[] values = {"Hello","World"}; RecyclerAdapter recyclerAdapter = new RecyclerAdapter(values, new RecyclerAdapter.ClickCallback() { @Override public void onItemClick(int position) { // Do anything with the item position } });

Eso es todo para mí. :)


Resolví de esta manera

class MyOnClickListener implements View.OnClickListener { @Override public void onClick(View v) { int itemPosition = mRecyclerView.getChildAdapterPosition(v); myResult = results.get(itemPosition); } }

Y en el adaptador

@Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_wifi, parent, false); v.setOnClickListener(new MyOnClickListener()); ViewHolder vh = new ViewHolder(v); return vh; }


Se llama a onBindViewHolder () para todos y cada uno de los elementos y configurar el detector de clics dentro de onBindVieHolder () es una opción innecesaria para repetir cuando puede llamarlo una vez en su constructor ViewHolder.

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ public final TextView textView; public MyViewHolder(View view){ textView = (TextView) view.findViewById(R.id.text_view); view.setOnClickListener(this); // getAdapterPosition() retrieves the position here. } @Override public void onClick(View v){ // Clicked on item Toast.makeText(mContext, "Clicked on position: " + getAdapterPosition(), Toast.LENGTH_SHORT).show(); } }


Un método diferente: utilizando los métodos setTag () y getTag () de la clase View.

  1. use setTag () en el método onBindViewHolder de su adaptador

    @Override public void onBindViewHolder(myViewHolder viewHolder, int position) { viewHolder.mCardView.setTag(position); }

    donde mCardView se define en la clase myViewHolder

    private class myViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public View mCardView; public myViewHolder(View view) { super(view); mCardView = (CardView) view.findViewById(R.id.card_view); mCardView.setOnClickListener(this); } }

  2. use getTag () en su implementación OnClickListener

    @Override public void onClick(View view) { int position = (int) view.getTag(); //display toast with position of cardview in recyclerview list upon click Toast.makeText(view.getContext(),Integer.toString(position),Toast.LENGTH_SHORT).show(); }

vea https://.com/a/33027953/4658957 para más detalles


1. Crear nombre de clase RecyclerTouchListener.java

import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private GestureDetector gestureDetector; private ClickListener clickListener; public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) { this.clickListener = clickListener; gestureDetector = 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 && clickListener != null) { clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onClick(child, rv.getChildAdapterPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, int position); } }

2. Llame a RecyclerTouchListener

recycleView.addOnItemTouchListener(new RecyclerTouchListener(this, recycleView, new RecyclerTouchListener.ClickListener() { @Override public void onClick(View view, int position) { Toast.makeText(MainActivity.this,Integer.toString(position),Toast.LENGTH_SHORT).show(); } @Override public void onLongClick(View view, int position) { } }));


public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { FrameLayout root; public ViewHolder(View itemView) { super(itemView); root = (FrameLayout) itemView.findViewById(R.id.root); root.setOnClickListener(this); } @Override public void onClick(View v) { LogUtils.errorLog("POS_CLICKED: ",""+getAdapterPosition()); } }