Java Android RecyclerView 添加和删除项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26076965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android RecyclerView addition & removal of items
提问by Twentyonehundred
I have a RecyclerView with an TextView text box and a cross button ImageView. I have a button outside of the recyclerview that makes the cross button ImageView visible / gone.
我有一个带有 TextView 文本框和十字按钮 ImageView 的 RecyclerView。我在 recyclerview 之外有一个按钮,使十字按钮 ImageView 可见/消失。
I'm looking to remove an item from the recylerview, when that items cross button ImageView is pressed.
我希望从 recylerview 中删除一个项目,当该项目交叉按钮 ImageView 被按下时。
My adapter:
我的适配器:
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);
}
}
}
My layout is:
我的布局是:
<?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>
How can I get something like an onClick working for my crossButton ImageView? Is there a better way? Maybe changing the whole item onclick into a remove the item? The recyclerview shows a list of locations that need to be edited. Any technical advice or comments / suggestions on best implementation would be hugely appreciated.
我怎样才能得到像 onClick 这样的东西为我的 crossButton ImageView 工作?有没有更好的办法?也许将整个项目 onclick 更改为删除项目?recyclerview 显示需要编辑的位置列表。任何关于最佳实施的技术建议或评论/建议将不胜感激。
采纳答案by paradite
I have done something similar.
In your MyAdapter
:
我做过类似的事情。在您的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());
}
Hope this helps.
希望这可以帮助。
Edit:
编辑:
getPosition()
is deprecated now, use getAdapterPosition()
instead.
getPosition()
现在已弃用,请getAdapterPosition()
改用。
回答by Zahra.HY
first of all, item should be removed from the list!
首先,项目应该从列表中删除!
mDataSet.remove(getAdapterPosition());
then:
然后:
notifyItemRemoved(getAdapterPosition());
notifyItemRangeChanged(getAdapterPosition(),mDataSet.size());
回答by Arun
I tried all the above answers, but inserting or removing items to recyclerview causes problem with the position in the dataSet. Ended up using delete(getAdapterPosition());
inside the viewHolder which worked great at finding the position of items.
我尝试了上述所有答案,但是将项目插入或删除到 recyclerview 会导致数据集中的位置出现问题。最终delete(getAdapterPosition());
在 viewHolder 内部使用 ,它在查找项目的位置方面效果很好。
回答by Horatio
The problem I had was I was removing an item from the list that was no longer associated with the adapter to make sure you are modifying the correct adapter you can implement a method like this in your adapter:
我遇到的问题是我从列表中删除了一个不再与适配器关联的项目,以确保您正在修改正确的适配器,您可以在适配器中实现这样的方法:
public void removeItemAtPosition(int position) {
items.remove(position);
}
And call it in your fragment or activity like this:
并在您的片段或活动中调用它,如下所示:
adapter.removeItemAtPosition(position);
回答by Mostafa Anter
if still item not removed use this magic method :)
如果仍然没有删除项目,请使用此魔术方法:)
private void deleteItem(int position) {
mDataSet.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataSet.size());
holder.itemView.setVisibility(View.GONE);
}
Kotlin version
科特林版
private fun deleteItem(position: Int) {
mDataSet.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, mDataSet.size)
holder.itemView.visibility = View.GONE
}
回答by Hassan Jamil
Possibly a duplicate answer but quite useful for me. You can implement the method given below in RecyclerView.Adapter<RecyclerView.ViewHolder>
and can use this method as per your requirements, I hope it will work for you
可能是重复的答案,但对我来说非常有用。您可以实现下面给出的方法,RecyclerView.Adapter<RecyclerView.ViewHolder>
并可以根据您的要求使用此方法,我希望它对您有用
public void removeItem(@NonNull Object object) {
mDataSetList.remove(object);
notifyDataSetChanged();
}
回答by Tarun Umath
String str = arrayList.get(position);
arrayList.remove(str);
MyAdapter.this.notifyDataSetChanged();
回答by Sayed Mohammad Amin Emrani
if you want to remove item you should do this: first remove item:
如果你想删除项目,你应该这样做:首先删除项目:
phones.remove(position);
in next step you should notify your recycler adapter that you remove an item by this code:
在下一步中,您应该通过以下代码通知您的回收器适配器您删除了一个项目:
notifyItemRemoved(position);
notifyItemRangeChanged(position, phones.size());
but if you change an item do this: first change a parameter of your object like this:
但是如果你改变一个项目,这样做:首先改变你的对象的参数,如下所示:
Service s = services.get(position);
s.done = "Cancel service";
services.set(position,s);
or new it like this :
或者像这样新的:
Service s = new Service();
services.set(position,s);
then notify your recycler adapter that you modify an item by this code:
然后通知您的回收器适配器您通过以下代码修改项目:
notifyItemChanged(position);
notifyItemRangeChanged(position, services.size());
hope helps you.
希望对你有帮助。
回答by Suragch
Here are some visual supplemental examples. See my fuller answerfor examples of adding and removing a range.
以下是一些视觉补充示例。有关添加和删除范围的示例,请参阅我的更完整答案。
Add single item
添加单项
Add "Pig" at index 2
.
在索引处添加“猪” 2
。
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
Remove single item
删除单个项目
Remove "Pig" from the list.
从列表中删除“猪”。
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
回答by Andrea Cioccarelli
Problem
问题
RecyclerView
is, by default, unaware of your dataset changes.
This means that whenever you make a deletion/addition on your data-list, those changes won't be reflected to your RecyclerView directly.
RecyclerView
默认情况下,不知道您的数据集更改。这意味着每当您对数据列表进行删除/添加时,这些更改都不会直接反映到您的 RecyclerView 中。
Solution
解决方案
RecyclerView offers you some methods to share your dataset state. This happens because a modification on your dataset does not imply a view change, and vice versa. The standard android APIs allow you to bind the process of data removal(for the purpose of the question) with the process of view removal.
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)
Best Approach
最佳方法
If you don't properly specify what happens on your addition/removal of items (talking about views), RecyclerView children are animated unresponsively because of a lack of information about how to move the different views around the list.
如果您没有正确指定添加/删除项目时会发生什么(谈论视图),由于缺乏有关如何在列表中移动不同视图的信息,RecyclerView 子项将无响应地进行动画处理。
Instead, the following code will precisely play the animation, just on the child that is being removed (And as a side note, for me it fixed any IndexOutOfBoundException
s, marked by the stacktrace as "data inconsistency")
相反,下面的代码将精确地播放动画,只是在被移除的孩子上(作为旁注,对我来说,它修复了任何IndexOutOfBoundException
s,由堆栈跟踪标记为“数据不一致”)
void remove(position: Int) {
dataset.removeAt(position)
notifyItemChanged(position)
notifyItemRangeRemoved(position, 1)
}
Under the hood, if we look into RecyclerView
we can find documentation explaining that the second parameter we have to pass is the number of items that are removedfrom the dataset, not the total number of items (As wrongly stated in some others information sources).
在幕后,如果我们查看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);
}