Android Recycler보기 항목 추가 및 제거


144

TextView 텍스트 상자와 십자 버튼 ImageView가있는 RecyclerView가 있습니다. 십자 버튼 ImageView를 표시 / 사라지게하는 recyclerview 외부에 버튼이 있습니다.

해당 항목의 교차 단추 ImageView를 누르면 recylerview에서 항목을 제거하려고합니다.

내 어댑터 :

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

내 레이아웃은 다음과 같습니다

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

crossButton ImageView에서 작동하는 onClick과 같은 것을 어떻게 얻을 수 있습니까? 더 좋은 방법이 있습니까? 클릭 한 번으로 전체 항목을 변경하여 항목을 제거 할 수 있습니까? recyclerview는 편집해야 할 위치 목록을 보여줍니다. 최상의 구현에 대한 기술 조언이나 의견 / 제안은 대단히 감사하겠습니다.


LINK 1 LINK 2 살펴보세요 U 도움이 될 수도 있습니다
SaravanaRaja


1
Github Happy code !!!! 에서이 예제를 볼 수 있습니다.
Cabezas 2012

답변:


267

나는 비슷한 일을했다. 당신의 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());
}

도움이 되었기를 바랍니다.

편집하다:

getPosition()더 이상 사용되지 않습니다 getAdapterPosition(). 대신 사용하십시오.


50
또한 notifyItemRangeChanged(getPosition, mDataSet.size());항목을 제거한 후 paradite의 답변 에 추가 하여 제거 된 항목 아래의 모든보기가 그에 따라 조정되도록 할 것입니다.
Chris Angell

3
나는 같은 문제가 있지만 getPosition()이제는 더 이상 사용되지 않습니다
chip

4
고마워, 분명히 전화하는 것만으로 notifyItemRemoved(position)는 충분하지 않았습니다.
Ektos974

3
@chip 사용 getAdapterPosition ()
Tyler Pfaff

2
이 코드는 위와 아래에서 항목을 빠르게 제거 할 때 문제를 해결하지 않습니다.
Vito Valov

61

우선, 목록에서 항목을 제거해야합니다!

  mDataSet.remove(getAdapterPosition());

그때:

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

2
감사합니다. 더 많은 값을 추가해야한다고 가정 해 보겠습니다.
MohanRaj S

어댑터의 목록 크기와 관련이 있습니다. @ Hammad Nasir
Zahra.HY

나는 똑같이했지만 recyclerview 높이는 동적으로 변경되지 않았습니다. mNotes.remove (위치); notifyItemRemoved (위치); notifyItemRangeChanged (위치, getItemCount ()); @ Zahra.HY는 내가 놓친 부분이 있습니다.
Hitesh Dhamshaniya

22

여전히 항목이 제거되지 않으면이 마법 방법을 사용하십시오 :)

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

코 틀린 버전

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

@Mostafa : 10 개의 항목이 있고 마지막 시나리오를 제거한다고 가정합니다. 해당 시나리오에서 holder.itemView.setVisibility (View.GONE), 모든 데이터 숨기기
Hitesh Dhamshaniya

@HiteshDhamshaniya 아니 그냥 숨겨 마지막보기를 갔다
Mostafa Anter

보기를 숨길 필요가 없습니다. dataSet.remove (위치)의 벌금을 작동하지만 요이는 (dataset.size () - 1) notifyDatasetChamged () 또는 notifyItemRemoved 호출 할 필요가
Karue 벤슨 Karue

holder.itemView.setVisibility (View.GONE)에 감사드립니다;
K.Hayoev

10

문제

RecyclerView기본적으로 데이터 세트 변경 사항을 인식하지 못합니다. 즉, 데이터 목록에서 삭제 / 추가 할 때마다 해당 변경 사항이 RecyclerView에 직접 반영되지 않습니다.

해결책

RecyclerView는 데이터 세트 상태를 공유하는 몇 가지 방법을 제공합니다. 이는 데이터 세트의 수정이 뷰 변경을 의미하지 않으며 그 반대도 마찬가지입니다. 표준 Android API를 사용하면 데이터 제거 프로세스 (질문의 목적으로)를 뷰 제거 프로세스와 바인딩 할 수 있습니다 .

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

최고의 접근법

항목 추가 / 제거시 발생하는 상황 (뷰에 대한 대화)을 제대로 지정하지 않으면 목록에서 다른 뷰를 이동하는 방법에 대한 정보가 없기 때문에 RecyclerView 하위 애니메이션이 응답하지 않습니다.

대신, 다음 코드는 제거되는 자식에서만 애니메이션을 정확하게 재생합니다 (그리고 부수적으로 IndexOutOfBoundException스택 추적에 의해 "데이터 불일치"로 표시된 s를 수정했습니다 )

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

RecyclerView두 번째 매개 변수를 살펴보면 전달해야 할 두 번째 매개 변수가 총 항목 수가 아닌 데이터 집합에서 제거 된 항목 수라는 사실을 설명하는 문서를 찾을 수 있습니다 (일부 다른 정보 소스에서 잘못 언급 됨).

    /**
     * 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

아마도 중복 답변이지만 나에게 매우 유용합니다. 아래에 주어진 방법을 구현하고 RecyclerView.Adapter<RecyclerView.ViewHolder> 요구 사항에 따라이 방법을 사용할 수 있습니다.

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

5

다음은 시각적 보충 예입니다. 범위 추가 및 제거에 대한 예제는 전체 답변 을 참조하십시오 .

단일 아이템 추가

index에 "Pig"를 추가하십시오 2.

단일 항목 삽입

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

단일 항목 제거

목록에서 "Pig"를 제거하십시오.

단일 항목 제거

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

4

위의 모든 답변을 시도했지만 recyclerview에 항목을 삽입하거나 제거하면 dataSet의 위치에 문제가 발생합니다. delete(getAdapterPosition());viewHolder 내부에서 사용하여 항목 위치를 찾는 데 효과적이었습니다.


1
리스너를 설정하고 뷰 홀더 내부에서 getAdapterPosition () 메소드를 사용하십시오. 항목의 위치를 ​​반환합니다.
Arun

4

내가 가진 문제는 더 이상 어댑터와 관련이없는 목록에서 항목을 제거하여 올바른 어댑터를 수정했는지 확인한 것입니다. 어댑터에서 다음과 같은 방법을 구현할 수 있습니다.

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

다음과 같이 조각이나 활동에서 호출하십시오.

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

나는 이것이 당신을 돕기를 바랍니다.


1

항목을 제거하려면 다음을 수행하십시오. 먼저 항목을 제거하십시오.

phones.remove(position);

다음 단계에서는이 코드로 품목을 제거한다는 것을 재활용 어댑터에 알려야합니다.

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

그러나 항목을 변경하면 다음과 같이하십시오 : 먼저 다음과 같이 객체의 매개 변수를 변경하십시오.

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

또는 다음과 같이 새로운 :

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

그런 다음이 코드로 품목을 수정했다는 것을 재활용 어댑터에 알리십시오.

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

희망은 당신을 도와줍니다.


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

항목이 많으면 눈에 띄게 지연 될 수 있으므로 항목을 완전히 다시 그립니다. 올바른 일은 전화하는 것 notifyItemRemoved(position)입니다.
미나스 미나

나중에 올바른 우리는 또한 notifyDataSetChanged () instated notifyItemRemoved (position)를 사용합니다
Tarun Umath

1

onBindViewHolder이 코드를 작성하는 방법

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

누군가가 Adapter 클래스 대신 Main 클래스에서 이와 같은 것을 구현하려는 경우 다음을 사용할 수 있습니다.

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

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

여기서 friendsListRecycler는 어댑터 이름입니다.


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

사용자 정의 어댑터 클래스에 인터페이스를 만들고 리사이클 러보기에서 클릭 이벤트 처리 ..

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

어댑터를 정의하고 아래 코드라고하는 재활용 뷰에 바인딩 한 후

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

0

getadapterposition () 메소드에서 어댑터 위치를 어디에서 얻을 수 있는지 궁금해하는 경우; 뷰 홀더 객체에 있으므로 코드를 다음과 같이 입력해야합니다.

mdataset.remove(holder.getadapterposition());

0

활동에서 :

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

어댑터에서 :

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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.