[java] Android Recycler보기 항목 추가 및 제거

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는 편집해야 할 위치 목록을 보여줍니다. 최상의 구현에 대한 기술 조언이나 의견 / 제안은 대단히 감사하겠습니다.



답변

나는 비슷한 일을했다. 당신의 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(). 대신 사용하십시오.


답변

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

  mDataSet.remove(getAdapterPosition());

그때:

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


답변

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

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
}


답변

문제

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


답변

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

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


답변

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

단일 아이템 추가

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


답변

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