Android Recycler Xem thêm & xóa các mục


144

Tôi có RecyclerView với hộp văn bản TextView và ImageView nút chéo. Tôi có một nút bên ngoài recyclerview làm cho nút chéo ImageView hiển thị / biến mất.

Tôi đang tìm cách xóa một mục khỏi recylerview, khi đó mục đó nhấn nút ImageView.

Bộ chuyển đổi của tôi:

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

Bố cục của tôi là:

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

Làm cách nào tôi có thể nhận được một cái gì đó giống như một onClick hoạt động cho ImageView crossButton của tôi? Có cách nào tốt hơn? Có thể thay đổi toàn bộ mục onclick thành một mục loại bỏ? Recyclerview hiển thị một danh sách các vị trí cần được chỉnh sửa. Bất kỳ lời khuyên kỹ thuật hoặc ý kiến ​​/ đề xuất về việc thực hiện tốt nhất sẽ được đánh giá cao.


Hãy xem LINK 1 LINK 2 nó có thể giúp U
SaravanaRaja


1
Bạn có thể xem ví dụ này trongGithub Happy !!!!
Cabezas

Câu trả lời:


266

Tôi đã làm một cái gì đó tương tự. Trong của bạn 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());
}

Hi vọng điêu nay co ich.

Biên tập:

getPosition()bây giờ không dùng nữa, sử dụng getAdapterPosition()thay thế.


50
bạn cũng sẽ muốn thêm notifyItemRangeChanged(getPosition, mDataSet.size());vào câu trả lời của thiên đường sau khi bạn xóa mục này để tất cả các chế độ xem bên dưới mục bị xóa sẽ điều chỉnh tương ứng.
Chris Angell

3
Tôi có cùng một vấn đề nhưng getPosition()hiện không được chấp nhận
chip

4
Cảm ơn, dường như chỉ gọi notifyItemRemoved(position)là không đủ.
Ektos974

3
@chip Sử dụng getAd CHƯƠNGP vị trí ()
Tyler Pfaff

2
mã này không khắc phục được sự cố khi bạn nhanh chóng xóa các mục từ cả trên và dưới.
Vito Valov

61

trước hết, mục nên được loại bỏ khỏi danh sách!

  mDataSet.remove(getAdapterPosition());

sau đó:

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

2
cảm ơn đại diện của bạn, giả sử tôi phải thêm nhiều giá trị hơn có nghĩa là tôi có thể làm gì cho điều đó.
MohanRaj S

nó liên quan đến kích thước của danh sách trong bộ chuyển đổi của bạn. @ Hammad Nasir
Zahra.HY

Tôi đã làm như vậy, nhưng chiều cao recyclerview không thay đổi. mNotes.remove (vị trí); notifyItemRemond (vị trí); notifyItemRangeChanged (vị trí, getItemCount ()); @ Zahra. Tôi đã bỏ lỡ bất cứ điều gì.
Hitesh Dhamshaniya

22

Nếu vật phẩm vẫn không bị xóa hãy sử dụng phương pháp kỳ diệu này :)

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

Phiên bản Kotlin

private fun deleteItem(position: Int) {
    mDataSet.removeAt(position)
    notifyItemRemoved(position)
    notifyItemRangeChanged(position, mDataSet.size)
    holder.itemView.visibility = View.GONE
}

@Mostafa: Giả sử tôi có 10 mục và tôi xóa mục cuối cùng, trong chủ sở hữu kịch bản đó.itemView.setVisibility (View.GONE), Ẩn tất cả dữ liệu,
Hitesh Dhamshaniya

@HiteshDhamshaniya không, nó chỉ ẩn và đi góc nhìn cuối cùng
Mostafa Anter

Không cần phải che giấu tầm nhìn. dataSet.remove (vị trí) hoạt động tốt, nhưng bạn cần gọi notifyDatasetChamged () hoặc notifyItemRemond (tập dữ liệu.size () - 1)
Karue Benson Karue

cảm ơn vì chủ sở hữu.itemView.setVisibility (View.GONE);
K.Hayoev

10

Vấn đề

RecyclerViewtheo mặc định, không biết về những thay đổi dữ liệu của bạn. Điều này có nghĩa là bất cứ khi nào bạn thực hiện xóa / bổ sung vào danh sách dữ liệu của mình, những thay đổi đó sẽ không được phản ánh trực tiếp đến RecyclerView của bạn.

Giải pháp

RecyclerView cung cấp cho bạn một số phương pháp để chia sẻ trạng thái dữ liệu của bạn. Điều này xảy ra vì một sửa đổi trên tập dữ liệu của bạn không có nghĩa là thay đổi chế độ xem và ngược lại. Các API Android tiêu chuẩn cho phép bạn liên kết quá trình xóa dữ liệu (cho mục đích của câu hỏi) với quá trình xóa chế độ xem.

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

Cách tiếp cận tốt nhất

Nếu bạn không chỉ định chính xác những gì xảy ra khi thêm / xóa các mục (nói về chế độ xem), trẻ em RecyclerView hoạt hình không phản hồi vì thiếu thông tin về cách di chuyển các chế độ xem khác nhau xung quanh danh sách.

Thay vào đó, đoạn mã sau sẽ phát chính xác hoạt hình, chỉ trên đứa trẻ đang bị xóa (Và như một lưu ý phụ, đối với tôi, nó đã sửa bất kỳ IndexOutOfBoundExceptions nào , được đánh dấu bởi stacktrace là "không thống nhất dữ liệu")

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

Trong phần giới thiệu, nếu chúng ta nhìn vào, RecyclerViewchúng ta có thể tìm thấy tài liệu giải thích rằng tham số thứ hai chúng ta phải vượt qua là số mục được xóa khỏi bộ dữ liệu, không phải tổng số mục (Như đã nêu sai trong một số nguồn thông tin khác).

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

7

Có thể là một câu trả lời trùng lặp nhưng khá hữu ích cho tôi. Bạn có thể thực hiện phương pháp được đưa ra dưới đây RecyclerView.Adapter<RecyclerView.ViewHolder> và có thể sử dụng phương pháp này theo yêu cầu của bạn, tôi hy vọng nó sẽ hiệu quả với bạn

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

5

Dưới đây là một số ví dụ bổ sung trực quan. Xem câu trả lời đầy đủ hơn của tôi để biết ví dụ về việc thêm và xóa một phạm vi.

Thêm mục duy nhất

Thêm "Lợn" tại chỉ mục 2.

Chèn một mục duy nhất

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

Xóa một mục duy nhất

Xóa "Lợn" khỏi danh sách.

Xóa một mục duy nhất

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

4

Tôi đã thử tất cả các câu trả lời ở trên, nhưng việc chèn hoặc xóa các mục để tái chế lại gây ra vấn đề với vị trí trong tập dữ liệu. Đã kết thúc bằng cách sử dụng delete(getAdapterPosition());bên trong viewHolder, công việc tuyệt vời trong việc tìm vị trí của các mục.


1
Chỉ cần đặt một trình lắng nghe và sử dụng phương thức getAd CHƯƠNGP vị trí () bên trong khung nhìn. Nó sẽ trả về vị trí của vật phẩm.
Arun

4

Vấn đề tôi gặp phải là tôi đã xóa một mục khỏi danh sách không còn được liên kết với bộ điều hợp để đảm bảo bạn đang sửa đổi bộ điều hợp chính xác mà bạn có thể thực hiện một phương pháp như thế này trong bộ điều hợp của mình:

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

Và gọi nó trong đoạn hoặc hoạt động của bạn như thế này:

adapter.removeItemAtPosition(position);

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

tôi hy vọng điều này sẽ giúp bạn


1

Nếu bạn muốn xóa mục, bạn nên làm điều này: trước tiên hãy xóa mục này:

phones.remove(position);

trong bước tiếp theo, bạn nên thông báo cho bộ điều hợp tái chế của mình rằng bạn xóa một mục bằng mã này:

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

nhưng nếu bạn thay đổi một mục, hãy làm điều này: trước tiên hãy thay đổi một tham số của đối tượng của bạn như thế này:

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

hoặc mới như thế này:

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

sau đó thông báo cho bộ điều hợp tái chế của bạn rằng bạn sửa đổi một mục bằng mã này:

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

hy vọng giúp bạn


1
  String str = arrayList.get(position);
  arrayList.remove(str);
  MyAdapter.this.notifyDataSetChanged();

Đây là một ý tưởng thực sự tồi tệ, vì bạn sẽ buộc phải vẽ lại toàn bộ các vật phẩm, với độ trễ đáng chú ý nếu bạn có nhiều vật phẩm. Điều chính xác cần làm là gọi notifyItemRemoved(position).
Minas Mina

ya chính xác của bạn, chúng tôi cũng sử dụng notifyItemRemond (vị trí) bắt nguồn từ notifyDataSetChanged ()
Tarun Umath

1

Để Phương pháp onBindViewHolderViết mã này

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

1

Bất cứ ai cũng muốn thực hiện một cái gì đó như thế này trong lớp Main thay vì lớp Adaptor, bạn có thể sử dụng:

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

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

trong đó friendsListRecycler là tên Adaptor


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

0

tạo giao diện thành lớp bộ điều hợp tùy chỉnh và xử lý sự kiện nhấp chuột trên chế độ xem tái chế ..

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

sau khi xác định bộ điều hợp và liên kết vào chế độ xem tái chế được gọi dưới đây mã ..

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

0

Trong trường hợp bạn đang tự hỏi như tôi đã làm ở đâu chúng ta có thể có được vị trí bộ điều hợp trong phương thức getad CHƯƠNGposeition (); Nó trong viewholder object. vì vậy bạn phải đặt mã của mình như thế này

mdataset.remove(holder.getadapterposition());

0

Trong hoạt động:

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

Trong bộ chuyển đổi của bạn:

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.