选中复选框时如何将项目移动到最后一个位置? (回收视图,ViewHolder)
How to move item to the last position when Checkbox is checked? (RecyclerView, ViewHolder)
我尝试制作一个包含复选框的 RecyclerView(如果已购买)。我想将项目移动到 CheckBox 选中更改的最后位置并将背景设置为绿色。我试图从 ArrayList 中删除项目,然后再次添加它,但它只适用于字符串名称,它不保持状态(复选框状态或颜色)。其他时候它会抛出 Exception: Cannot call this method while RecyclerView is computing a layout or scrolling。有人可以告诉我我做错了什么吗?
对不起我的英语。
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>
{
private ArrayList<String> mDataset;
private ArrayList<FinalListItem> finalListItems;
public MyAdapter(ArrayList<String> mDataset) {
this.mDataset = mDataset;
[enter image description here][1]finalListItems = new ArrayList<>();
for (String a : mDataset) {
finalListItems.add(new FinalListItem(a, false));
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.final_list_TextView1.setText(finalListItems.get(position).getName());
if(finalListItems.get(position).isChecked){
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
}
else{
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
FinalListItem finalItem = new FinalListItem(finalListItems.get(position).getName(),true);
if (isChecked) {
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
finalListItems.remove(finalListItems.get(position));
finalListItems.add(finalItem);
notifyDataSetChanged(); //weird behaviour of app
} else {
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
}
}
});
}
@Override
public int getItemCount() {
return finalListItems.size();
}
private class FinalListItem {
private String name;
private boolean isChecked;
public FinalListItem(String name, boolean isChecked) {
this.name = name;
this.isChecked = isChecked;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
public String getName() {
return name;
}
}
public class MyViewHolder extends RecyclerView.ViewHolder {
final public TextView final_list_TextView1;
final public CheckBox checkBox;
final public LinearLayout linearLayout;
public MyViewHolder(View view) {
super(view);
final_list_TextView1 = (TextView) view.findViewById(R.id.final_list_TextView1);
checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
linearLayout = (LinearLayout) view.findViewById(R.id.linearLayout1);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.finallist_list_layout, parent, false);
return new MyViewHolder(view);
}
}
你应该改变你的代码的主要事情是只改变数据然后让适配器根据改变的数据显示列表是很重要的。这意味着,你不应该改变,例如你自己的背景,但你应该改变 FinalListItem 的列表并通知适配器。
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.final_list_TextView1.setText(finalListItems.get(position).getName());
// remove the Listener before setting the checked state programmatically
// and set all the attributes (checked state and background color) here
holder.checkBox.setOnCheckedChangeListener(null);
if(finalListItems.get(position).isChecked){
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
holder.checkBox.setChecked(true);
}
else{
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
holder.checkBox.setChecked(false);
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Lint warning : don't use "final int position"
int currentPosition = holder.getAdapterPosition();
if (isChecked) {
FinalListItem finalItemBefore = finalListItems.get(currentPosition);
FinalListItem finalItemAfter = new FinalListItem(finalItemBefore.getName(),true);
finalListItems.remove(finalItemBefore);
finalListItems.add(finalItemAfter);
notifyDataSetChanged();
} else {
finalListItems.get(currentPosition).setChecked(false);
// no need to update the whole list since only one item has changed
notifyItemChanged(currentPosition);
}
}
});
}
另请注意,从 getItemViewType()
return position 不是一个好主意。通过这样做,您告诉运行时每个 View
都是唯一的并且回收 View
s 是不可能的,这对 RecyclerView
.
的性能不利。
您的列表的实现方式,一种 View
类型就足够了,因此您根本不需要重写该方法,因为这是默认实现:
@Override
public int getItemViewType(int position) {
return 0;
}
@0X0nosugar 回答正确:),我发现我们也可以使用
notifyItemRemoved(currentposition); //after removing an item
notifyItemInserted(currentposition); //after inserting an item
它为我们的适配器提供了好看流畅的动画。
我尝试制作一个包含复选框的 RecyclerView(如果已购买)。我想将项目移动到 CheckBox 选中更改的最后位置并将背景设置为绿色。我试图从 ArrayList 中删除项目,然后再次添加它,但它只适用于字符串名称,它不保持状态(复选框状态或颜色)。其他时候它会抛出 Exception: Cannot call this method while RecyclerView is computing a layout or scrolling。有人可以告诉我我做错了什么吗?
对不起我的英语。
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>
{
private ArrayList<String> mDataset;
private ArrayList<FinalListItem> finalListItems;
public MyAdapter(ArrayList<String> mDataset) {
this.mDataset = mDataset;
[enter image description here][1]finalListItems = new ArrayList<>();
for (String a : mDataset) {
finalListItems.add(new FinalListItem(a, false));
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.final_list_TextView1.setText(finalListItems.get(position).getName());
if(finalListItems.get(position).isChecked){
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
}
else{
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
FinalListItem finalItem = new FinalListItem(finalListItems.get(position).getName(),true);
if (isChecked) {
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
finalListItems.remove(finalListItems.get(position));
finalListItems.add(finalItem);
notifyDataSetChanged(); //weird behaviour of app
} else {
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
}
}
});
}
@Override
public int getItemCount() {
return finalListItems.size();
}
private class FinalListItem {
private String name;
private boolean isChecked;
public FinalListItem(String name, boolean isChecked) {
this.name = name;
this.isChecked = isChecked;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
public String getName() {
return name;
}
}
public class MyViewHolder extends RecyclerView.ViewHolder {
final public TextView final_list_TextView1;
final public CheckBox checkBox;
final public LinearLayout linearLayout;
public MyViewHolder(View view) {
super(view);
final_list_TextView1 = (TextView) view.findViewById(R.id.final_list_TextView1);
checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
linearLayout = (LinearLayout) view.findViewById(R.id.linearLayout1);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.finallist_list_layout, parent, false);
return new MyViewHolder(view);
}
}
你应该改变你的代码的主要事情是只改变数据然后让适配器根据改变的数据显示列表是很重要的。这意味着,你不应该改变,例如你自己的背景,但你应该改变 FinalListItem 的列表并通知适配器。
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.final_list_TextView1.setText(finalListItems.get(position).getName());
// remove the Listener before setting the checked state programmatically
// and set all the attributes (checked state and background color) here
holder.checkBox.setOnCheckedChangeListener(null);
if(finalListItems.get(position).isChecked){
holder.linearLayout.setBackgroundColor(Color.rgb(0, 225, 0));
holder.checkBox.setChecked(true);
}
else{
holder.linearLayout.setBackgroundColor(Color.rgb(255, 255, 255));
holder.checkBox.setChecked(false);
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Lint warning : don't use "final int position"
int currentPosition = holder.getAdapterPosition();
if (isChecked) {
FinalListItem finalItemBefore = finalListItems.get(currentPosition);
FinalListItem finalItemAfter = new FinalListItem(finalItemBefore.getName(),true);
finalListItems.remove(finalItemBefore);
finalListItems.add(finalItemAfter);
notifyDataSetChanged();
} else {
finalListItems.get(currentPosition).setChecked(false);
// no need to update the whole list since only one item has changed
notifyItemChanged(currentPosition);
}
}
});
}
另请注意,从 getItemViewType()
return position 不是一个好主意。通过这样做,您告诉运行时每个 View
都是唯一的并且回收 View
s 是不可能的,这对 RecyclerView
.
您的列表的实现方式,一种 View
类型就足够了,因此您根本不需要重写该方法,因为这是默认实现:
@Override
public int getItemViewType(int position) {
return 0;
}
@0X0nosugar 回答正确:),我发现我们也可以使用
notifyItemRemoved(currentposition); //after removing an item
notifyItemInserted(currentposition); //after inserting an item
它为我们的适配器提供了好看流畅的动画。