Penambahan & penghapusan Android RecyclerView item

144

Saya memiliki RecyclerView dengan kotak teks TextView dan tombol silang ImageView. Saya memiliki tombol di luar recyclerview yang membuat tombol silang ImageView terlihat / hilang.

Saya mencari untuk menghapus item dari recylerview, ketika tombol item lintas itu ImageView ditekan.

Adaptor saya:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener, View.OnLongClickListener {

    private ArrayList<String> mDataset;
    private static Context sContext;

    public MyAdapter(Context context, ArrayList<String> 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);
        }
    }
}

Layout saya adalah:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:id="@+id/layout">

    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:padding="5dp"
        android:background="@drawable/greyline"/>

    <ImageView
        android:id="@+id/crossButton"
        android:layout_width="16dp"
        android:layout_height="16dp"
        android:visibility="gone"
        android:layout_marginLeft="50dp"
        android:src="@drawable/cross" />
</LinearLayout>

Bagaimana saya bisa mendapatkan sesuatu seperti onClick yang berfungsi untuk ImageView crossButton saya? Apakah ada cara yang lebih baik? Mungkin mengubah seluruh item di klik menjadi menghapus item? Recyclerview menunjukkan daftar lokasi yang perlu diedit. Setiap saran teknis atau komentar / saran tentang implementasi terbaik akan sangat dihargai.

Dua puluh satu ratus
sumber
Lihatlah LINK 1 LINK 2 ini mungkin membantu U
SaravanaRaja
1
Anda dapat melihat contoh ini dalam kode Github Happy !!!!
Cabezas

Jawaban:

267

Saya telah melakukan hal serupa. Di Anda 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());
}

Semoga ini membantu.

Edit:

getPosition()sudah ditinggalkan sekarang, gunakan getAdapterPosition()saja.

paradigma
sumber
50
Anda juga ingin menambahkan notifyItemRangeChanged(getPosition, mDataSet.size());jawaban paraditet setelah Anda menghapus item sehingga semua tampilan di bawah item yang dihapus akan menyesuaikan sesuai.
Chris Angell
3
saya memiliki masalah yang sama tetapi getPosition()sekarang sudah tidak digunakan lagi
chip
4
Terima kasih, ternyata hanya menelepon saja notifyItemRemoved(position)tidak cukup.
Ektos974
3
@chip Pakai getAdapterPosition ()
Tyler Pfaff
2
kode ini tidak memperbaiki masalah ketika Anda dengan cepat menghapus item dari atas dan bawah.
Vito Valov
60

pertama-tama, item harus dihapus dari daftar!

  mDataSet.remove(getAdapterPosition());

kemudian:

  notifyItemRemoved(getAdapterPosition());
  notifyItemRangeChanged(getAdapterPosition(),mDataSet.size());
Zahra. HY
sumber
2
terima kasih banyak Anda, misalkan saya harus menambahkan lebih banyak nilai berarti apa yang bisa saya lakukan untuk itu.
MohanRaj S
ini terkait dengan ukuran daftar di adaptor Anda. @ Hammad Nasir
Zahra. HY
Saya melakukan hal yang sama, tetapi ketinggian recyclerview tidak berubah secara dinamis. mNotes.remove (posisi); notifyItemRemoved (posisi); notifyItemRangeChanged (position, getItemCount ()); @ Zahra. DIA saya melewatkan sesuatu.
Hitesh Dhamshaniya
22

jika masih item tidak dihapus gunakan metode ajaib ini :)

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

Versi Kotlin

private fun deleteItem(position: Int) {
    mDataSet.removeAt(position)
    notifyItemRemoved(position)
    notifyItemRangeChanged(position, mDataSet.size)
    holder.itemView.visibility = View.GONE
}
Mostafa Anter
sumber
@Mostafa: Misalkan saya punya 10 item dan saya menghapus yang terakhir, dalam skenario itu holder.itemView.setVisibility (View.GONE), Sembunyikan semua data,
Hitesh Dhamshaniya
@HiteshDhamshaniya tidak hanya menyembunyikan dan pergi pandangan terakhir
Mostafa Anter
Tidak perlu menyembunyikan tampilan. dataSet.remove (posisi) berfungsi dengan baik, tetapi Anda perlu memanggil notifyDatasetChamged () atau notifyItemRemoved (dataset.size () - 1)
Karue Benson Karue
terima kasih untuk holder.itemView.setVisibility (View.GONE);
K.Hayoev
10

Masalah

RecyclerViewsecara default tidak mengetahui perubahan dataset Anda. Ini berarti bahwa setiap kali Anda membuat penghapusan / penambahan pada daftar data Anda, perubahan itu tidak akan langsung tercermin ke RecyclerView Anda.

Larutan

RecyclerView menawarkan beberapa metode untuk membagikan keadaan dataset Anda. Ini terjadi karena modifikasi pada dataset Anda tidak menyiratkan perubahan tampilan, dan sebaliknya. API Android standar memungkinkan Anda untuk mengikat proses penghapusan data (untuk tujuan pertanyaan) dengan proses penghapusan tampilan.

notifyItemChanged(index: Int)
notifyItemInserted(index: Int)
notifyItemRemoved(index: Int)
notifyItemRangeChanged(startPosition: Int, itemCount: Int)
notifyItemRangeInserted(startPosition: Int, itemCount: Int)
notifyItemRangeRemoved(startPosition: Int, itemCount: Int)

Pendekatan Terbaik

Jika Anda tidak menentukan dengan tepat apa yang terjadi pada penambahan / penghapusan item Anda (berbicara tentang tampilan), anak-anak RecyclerView dianimasikan secara tidak responsif karena kurangnya informasi tentang cara memindahkan berbagai tampilan di sekitar daftar.

Sebagai gantinya, kode berikut justru akan memutar animasi, hanya pada anak yang sedang dihapus (Dan sebagai catatan, bagi saya itu memperbaiki apa pun IndexOutOfBoundException, ditandai oleh stacktrace sebagai "inkonsistensi data")

void remove(position: Int) {
    dataset.removeAt(position)
    notifyItemChanged(position)
    notifyItemRangeRemoved(position, 1)
}

Di bawah tenda, jika kita melihat ke dalam RecyclerViewkita dapat menemukan dokumentasi yang menjelaskan bahwa parameter kedua yang harus kita lewati adalah jumlah item yang dihapus dari dataset, bukan jumlah total item (Seperti yang dinyatakan secara salah dalam beberapa sumber informasi lainnya).

    /**
     * Notify any registered observers that the <code>itemCount</code> items previously
     * located at <code>positionStart</code> have been removed from the data set. The items
     * previously located at and after <code>positionStart + itemCount</code> may now be found
     * at <code>oldPosition - itemCount</code>.
     *
     * <p>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.</p>
     *
     * @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);
    }
Andrea Cioccarelli
sumber
7

Mungkin jawaban rangkap tapi cukup berguna bagi saya. Anda dapat menerapkan metode yang diberikan di bawah ini RecyclerView.Adapter<RecyclerView.ViewHolder> dan dapat menggunakan metode ini sesuai kebutuhan Anda, saya harap ini akan berhasil untuk Anda

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

Berikut adalah beberapa contoh tambahan visual. Lihat jawaban lengkap saya untuk contoh menambah dan menghapus rentang.

Tambahkan satu item

Tambahkan "Babi" di indeks 2.

Sisipkan satu item

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

Hapus satu item

Hapus "Babi" dari daftar.

Hapus satu item

int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
Suragch
sumber
4

Saya mencoba semua jawaban di atas, tetapi memasukkan atau menghapus item ke recyclerview menyebabkan masalah dengan posisi di set data. Akhirnya menggunakan delete(getAdapterPosition());di dalam viewHolder yang bekerja sangat baik dalam menemukan posisi item.

Arun
sumber
1
Cukup atur pendengar dan gunakan metode getAdapterPosition () di dalam view view. Ini akan mengembalikan posisi item.
Arun
4

Masalah yang saya miliki adalah saya menghapus item dari daftar yang tidak lagi dikaitkan dengan adaptor untuk memastikan Anda memodifikasi adaptor yang benar Anda dapat menerapkan metode seperti ini di adaptor Anda:

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

Dan menyebutnya dalam fragmen atau aktivitas Anda seperti ini:

adapter.removeItemAtPosition(position);
Horatio
sumber
2
  public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private List<cardview_widgets> list;

public MyAdapter(Context context, List<cardview_widgets> list) {
    this.context = context;
    this.list = list;
}

@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(this.context).inflate(R.layout.fragment1_one_item,
            viewGroup, false);
    return new MyViewHolder(view);
}

public static class MyViewHolder extends RecyclerView.ViewHolder {
    TextView txt_value;
    TextView txt_category;
    ImageView img_inorex;
    ImageView img_category;
    TextView txt_date;

    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        txt_value = itemView.findViewById(R.id.id_values);
        txt_category = itemView.findViewById(R.id.id_category);
        img_inorex = itemView.findViewById(R.id.id_inorex);
        img_category = itemView.findViewById(R.id.id_imgcategory);
        txt_date = itemView.findViewById(R.id.id_date);
    }
}

@NonNull
@Override
public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int i) {

    myViewHolder.txt_value.setText(String.valueOf(list.get(i).getValuee()));
    myViewHolder.txt_category.setText(list.get(i).getCategory());
    myViewHolder.img_inorex.setBackgroundColor(list.get(i).getImg_inorex());
    myViewHolder.img_category.setImageResource(list.get(i).getImg_category());
    myViewHolder.txt_date.setText(list.get(i).getDate());
    myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            list.remove(myViewHolder.getAdapterPosition());
            notifyDataSetChanged();
            return false;
        }
    });
}

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

Saya harap ini membantu Anda.

Mohamed Ben Romdhane
sumber
1

jika Anda ingin menghapus item Anda harus melakukan ini: pertama hapus item:

phones.remove(position);

pada langkah selanjutnya Anda harus memberi tahu adaptor pendaur ulang bahwa Anda menghapus item dengan kode ini:

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

tetapi jika Anda mengubah item, lakukan ini: pertama-tama ubah parameter objek Anda seperti ini:

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

atau baru seperti ini:

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

kemudian beri tahu adaptor pendaur ulang bahwa Anda memodifikasi item dengan kode ini:

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

semoga membantu anda.

Sayed Mohammad Amin Emrani
sumber
1
  String str = arrayList.get(position);
  arrayList.remove(str);
  MyAdapter.this.notifyDataSetChanged();
Tarun Umath
sumber
Ini adalah ide yang sangat buruk, karena Anda akan memaksa undian ulang penuh item, dengan lag yang mungkin terlihat jika Anda memiliki banyak item. Yang benar untuk dilakukan adalah menelepon notifyItemRemoved(position).
Minas Mina
ya Anda benar, kami juga menggunakan notifyItemRemoved (posisi) yang diinput dari notifyDataSetChanged ()
Tarun Umath
1

Untuk Metode onBindViewHolderTulis Kode Ini

holder.remove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Cursor del=dbAdapter.ExecuteQ("delete from TblItem where Id="+values.get(position).getId());
                values.remove(position);
                notifyDataSetChanged();
            }
        });
Diako Hasani
sumber
1

Jika Anda ingin menerapkan sesuatu seperti ini di kelas Utama alih-alih kelas Adaptor, Anda dapat menggunakan:

public void removeAt(int position) {
    peopleListUser.remove(position);

    friendsListRecycler.getAdapter().notifyItemRemoved(position);
    friendsListRecycler.getAdapter().notifyItemRangeChanged(position, peopleListUser.size());
}

di mana friendsListRecycler adalah nama Adaptor

Baba hutan
sumber
0
 //////// 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();
                }
            });
roshan posakya
sumber
0

membuat antarmuka menjadi kelas adaptor khusus dan menangani acara klik pada tampilan pendaur ulang ..

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

setelah mendefinisikan adaptor dan mengikat ke tampilan pendaur ulang yang disebut kode di bawah ini ..

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

Jika Anda bertanya-tanya seperti yang saya lakukan di mana kita bisa mendapatkan posisi adaptor dalam metode getadapterposition (); itu di viewholder object.so Anda harus meletakkan kode Anda seperti ini

mdataset.remove(holder.getadapterposition());
raj kavadia
sumber
0

Dalam kegiatan:

mAdapter.updateAt(pos, text, completed);
mAdapter.removeAt(pos);

Di adaptor Anda:

void removeAt(int position) {
    list.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, list.size());
}

void updateAt(int position, String text, Boolean completed) {
    TodoEntity todoEntity = list.get(position);
    todoEntity.setText(text);
    todoEntity.setCompleted(completed);
    notifyItemChanged(position);
}
Huy Nguyen
sumber