Android RecyclerView adición y eliminación de elementos

Tengo un RecyclerView con un cuadro de texto TextView y un botón de imagen ImageView. Tengo un botón fuera de la vista de reciclador que hace visible el botón cruzado ImageView.

Estoy tratando de eliminar un elemento de la vista de reciclado, cuando se presiona el botón de elementos cruzados ImageView.

Mi adaptador:

public class MyAdapter extends RecyclerView.Adapter implements View.OnClickListener, View.OnLongClickListener { private ArrayList mDataset; private static Context sContext; public MyAdapter(Context context, ArrayList myDataset) { mDataset = myDataset; sContext = context; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_text_view, parent, false); ViewHolder holder = new ViewHolder(v); holder.mNameTextView.setOnClickListener(MyAdapter.this); holder.mNameTextView.setOnLongClickListener(MyAdapter.this); holder.mNameTextView.setTag(holder); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mNameTextView.setText(mDataset.get(position)); } @Override public int getItemCount() { return mDataset.size(); } @Override public void onClick(View view) { ViewHolder holder = (ViewHolder) view.getTag(); if (view.getId() == holder.mNameTextView.getId()) { Toast.makeText(sContext, holder.mNameTextView.getText(), Toast.LENGTH_SHORT).show(); } } @Override public boolean onLongClick(View view) { ViewHolder holder = (ViewHolder) view.getTag(); if (view.getId() == holder.mNameTextView.getId()) { mDataset.remove(holder.getPosition()); notifyDataSetChanged(); Toast.makeText(sContext, "Item " + holder.mNameTextView.getText() + " has been removed from list", Toast.LENGTH_SHORT).show(); } return false; } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mNumberRowTextView; public TextView mNameTextView; public ViewHolder(View v) { super(v); mNameTextView = (TextView) v.findViewById(R.id.nameTextView); } } } 

Mi diseño es:

      

¿Cómo puedo obtener algo como un onClick que funcione para mi crossButton ImageView? ¿Hay una mejor manera? ¿Tal vez cambiar todo el elemento haciendo clic en un elemento eliminar? La vista de reciclador muestra una lista de ubicaciones que deben editarse. Cualquier consejo técnico o comentario / sugerencia sobre la mejor implementación sería muy apreciado.

He hecho algo similar. En tu MyAdapter :

 public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ public CardView mCardView; public TextView mTextViewTitle; public TextView mTextViewContent; public ImageView mImageViewContentPic; //...... public ImageView imgViewRemoveIcon; public ViewHolder(View v) { super(v); mCardView = (CardView) v.findViewById(R.id.card_view); mTextViewTitle = (TextView) v.findViewById(R.id.item_title); mTextViewContent = (TextView) v.findViewById(R.id.item_content); mImageViewContentPic = (ImageView) v.findViewById(R.id.item_content_pic); //...... imgViewRemoveIcon = (ImageView) v.findViewById(R.id.remove_icon); mTextViewContent.setOnClickListener(this); imgViewRemoveIcon.setOnClickListener(this); v.setOnClickListener(this); mTextViewContent.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { if (mItemClickListener != null) { mItemClickListener.onItemClick(view, getPosition()); } return false; } }); } @Override public void onClick(View v) { //Log.d("View: ", v.toString()); //Toast.makeText(v.getContext(), mTextViewTitle.getText() + " position = " + getPosition(), Toast.LENGTH_SHORT).show(); if(v.equals(imgViewRemoveIcon)){ removeAt(getPosition()); }else if (mItemClickListener != null) { mItemClickListener.onItemClick(v, getPosition()); } } } public void setOnItemClickListener(final OnItemClickListener mItemClickListener) { this.mItemClickListener = mItemClickListener; } public void removeAt(int position) { mDataset.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(position, mDataSet.size()); } 

Espero que esto ayude.

Editar:

getPosition() está privado ahora use getAdapterPosition() lugar.

¡antes que nada, el artículo debería ser eliminado de la lista!

  mDataSet.remove(getAdapterPosition()); 

entonces:

  notifyItemRemoved(getAdapterPosition()); notifyItemRangeChanged(getAdapterPosition(),mDataSet.size()); 

si todavía no se eliminó el elemento, utiliza este método mágico 🙂

 private void deleteItem(int position) { mDataSet.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(position, mDataSet.size()); holder.itemView.setVisibility(View.GONE); } 

Intenté todas las respuestas anteriores, pero insertar o eliminar elementos en la vista de reciclador causa problemas con la posición en el conjunto de datos. Terminó usando delete(getAdapterPosition()); dentro del viewHolder que funcionó muy bien para encontrar la posición de los artículos.

De hecho, con el código mencionado anteriormente (que puede encontrar aquí más abajo), todos los hijos de RecyclerView están animados cuando se elimina un solo elemento y no es una solución receptiva en absoluto, también porque tiene algunos posibles problemas ocultos.

 public void remove(int position) { dataset.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(position, mDataSet.size()); } 

En cambio, el siguiente fragmento reproducirá la animación solo en el elemento secundario que se está eliminando y, por mi parte, dejó de lanzar IndexOutOfBoundException s, marcado por el depurador como “incoherencia de datos”

 void remove(int position) { dataset.removeAt(position); notifyItemChanged(position); notifyItemRangeRemoved(position, 1); } 

Si profundizamos en la clase RecyclerView podemos encontrar un pice de javadoc que tiene la explicación, de hecho como segundo parámetro tenemos que pasar el número de elementos que se eliminan del conjunto de datos, no el número total de elementos

  /** * Notify any registered observers that the itemCount items previously * located at positionStart have been removed from the data set. The items * previously located at and after positionStart + itemCount may now be found * at oldPosition - itemCount. * * 

This is a structural change event. Representations of other existing items in the data * set are still considered up to date and will not be rebound, though their positions * may be altered.

* * @param positionStart Previous position of the first item that was removed * @param itemCount Number of items removed from the data set */ public final void notifyItemRangeRemoved(int positionStart, int itemCount) { mObservable.notifyItemRangeRemoved(positionStart, itemCount); }

El problema que tenía era que estaba eliminando un elemento de la lista que ya no estaba asociado con el adaptador para asegurarse de que está modificando el adaptador correcto; puede implementar un método como este en su adaptador:

 public void removeItemAtPosition(int position) { items.remove(position); } 

Y llámalo en tu fragmento o actividad como este:

 adapter.removeItemAtPosition(position); 

Posiblemente una respuesta duplicada pero bastante útil para mí. Puede implementar el método indicado a continuación en RecyclerView.Adapter y puede usar este método según sus requisitos, espero que funcione para usted

 public void removeItem(@NonNull Object object) { mDataSetList.remove(object); notifyDataSetChanged(); } 

Aquí hay algunos ejemplos suplementarios visuales. Consulte mi respuesta completa para ver ejemplos de cómo agregar y eliminar un rango.

Agregar un solo elemento

Agrega “Cerdo” en el índice 2 .

Insertar un solo elemento

 String item = "Pig"; int insertIndex = 2; data.add(insertIndex, item); adapter.notifyItemInserted(insertIndex); 

Eliminar un solo artículo

Retire “Cerdo” de la lista.

Eliminar un solo artículo

 int removeIndex = 2; data.remove(removeIndex); adapter.notifyItemRemoved(removeIndex); 
  String str = arrayList.get(position); arrayList.remove(str); MyAdapter.this.notifyDataSetChanged(); 

si desea eliminar el elemento, debe hacer esto: primero eliminar el elemento:

 phones.remove(position); 

En el siguiente paso, debe notificar a su adaptador de reciclador que elimina un artículo con este código:

 notifyItemRemoved(position); notifyItemRangeChanged(position, phones.size()); 

pero si cambia un ítem, haga lo siguiente: primero cambie un parámetro de su objeto como este:

 Service s = services.get(position); s.done = "Cancel service"; services.set(position,s); 

o nuevo como este:

 Service s = new Service(); services.set(position,s); 

luego notifique a su adaptador reciclador que usted modifica un artículo con este código:

 notifyItemChanged(position); notifyItemRangeChanged(position, services.size()); 

la esperanza te ayuda.

  //////// set the position holder.cancel.setTag(position); ///// click to remove an item from recycler view and an array list holder.cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int positionToRemove = (int)view.getTag(); //get the position of the view to delete stored in the tag mDataset.remove(positionToRemove); notifyDataSetChanged(); } }); 

hacer la interfaz en la clase de adaptador personalizado y manejar el evento click en la vista de reciclador …

  onItemClickListner onItemClickListner; public void setOnItemClickListner(CommentsAdapter.onItemClickListner onItemClickListner) { this.onItemClickListner = onItemClickListner; } public interface onItemClickListner { void onClick(Contact contact);//pass your object types. } @Override public void onBindViewHolder(ItemViewHolder holder, int position) { // below code handle click event on recycler view item. holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { onItemClickListner.onClick(mContectList.get(position)); } }); } 

después de definir el adaptador y vincularlo a la vista del reciclador que se llama debajo del código.

  adapter.setOnItemClickListner(new CommentsAdapter.onItemClickListner() { @Override public void onClick(Contact contact) { contectList.remove(contectList.get(contectList.indexOf(contact))); adapter.notifyDataSetChanged(); } }); }