Gun*_*lan 60 android android-recyclerview
我知道在recyclerview类中没有默认的选择方法,但是我试过以下方式,
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mTextView.setText(fonts.get(position).getName());
holder.checkBox.setChecked(fonts.get(position).isSelected());
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
for (int i = 0; i < fonts.size(); i++) {
fonts.get(i).setSelected(false);
}
fonts.get(position).setSelected(isChecked);
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
尝试这段代码时,我得到了预期的输出,但完全没有.
我将用图像解释这个.
默认情况下,从我的适配器中选择第一个项目

然后我试图选择第二个然后是第三个,然后是第四个,最后是第五个,

这里仅应选择第5个,但所有5个都被选中.
如果我将列表滚动到底部并再次返回顶部,

我得到了我的预期,
我怎样才能克服这个问题?还有一段时间如果我快速滚动列表,其他一些项目就会被选中.如何克服这个问题呢?
更新
notifyDataSetChanged()在fonts.get(position).setSelected(isChecked);我得到以下异常后,我正在尝试使用
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)
Run Code Online (Sandbox Code Playgroud)
Xci*_*egn 97
该问题的解决方案:
public class yourRecyclerViewAdapter extends RecyclerView.Adapter<yourRecyclerViewAdapter.yourViewHolder> {
private static CheckBox lastChecked = null;
private static int lastCheckedPos = 0;
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mTextView.setText(fonts.get(position).getName());
holder.checkBox.setChecked(fonts.get(position).isSelected());
holder.checkBox.setTag(new Integer(position));
//for default check in first item
if(position == 0 && fonts.get(0).isSelected() && holder.checkBox.isChecked())
{
lastChecked = holder.checkBox;
lastCheckedPos = 0;
}
holder.checkBox.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
CheckBox cb = (CheckBox)v;
int clickedPos = ((Integer)cb.getTag()).intValue();
if(cb.isChecked())
{
if(lastChecked != null)
{
lastChecked.setChecked(false);
fonts.get(lastCheckedPos).setSelected(false);
}
lastChecked = cb;
lastCheckedPos = clickedPos;
}
else
lastChecked = null;
fonts.get(clickedPos).setSelected(cb.isChecked);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
希望这有帮助!
sub*_*ati 75
它太晚了仍然发布它可能有助于其他人使用下面的代码作为参考检查RecyclerView中的单个项目
/**
* Created by subrahmanyam on 28-01-2016, 04:02 PM.
*/
public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> {
private final String[] list;
private int lastCheckedPosition = -1;
public SampleAdapter(String[] list) {
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.sample_layout, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.choiceName.setText(list[position]);
holder.radioButton.setChecked(position == lastCheckedPosition);
}
@Override
public int getItemCount() {
return list.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.choice_name)
TextView choiceName;
@Bind(R.id.choice_select)
RadioButton radioButton;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
radioButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lastCheckedPosition = getAdapterPosition();
//because of this blinking problem occurs so
//i have a suggestion to add notifyDataSetChanged();
// notifyItemRangeChanged(0, list.length);//blink list problem
notifyDataSetChanged();
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
Wil*_*iam 13
看起来有两件事在这里发挥作用:
我将分别解决每个问题.
基本上,在onBindViewHolder你给出一个已经初始化的ViewHolder,已经包含一个视图.这ViewHolder可能会或可能不会被以前绑定的一些数据!
在这里注意这段代码:
holder.checkBox.setChecked(fonts.get(position).isSelected());
Run Code Online (Sandbox Code Playgroud)
如果持有者先前已被绑定,则复选框已经有一个监听器,用于检查状态是否发生变化!这个听众正在被触发,这正是导致你的IllegalStateException.
一个简单的解决方案是在调用之前删除监听器setChecked.优雅的解决方案需要更多的视图知识 - 我鼓励您寻找一种更好的方法来处理它.
代码中的侦听器正在更改数据的状态,而不通知适配器任何后续更改.我不知道您的观点是如何运作的,所以这可能是也可能不是问题.通常,当数据状态发生变化时,您需要让适配器知道它.
RecyclerView.Adapter有很多选项可供选择,包括notifyItemChanged告诉它特定项目已改变状态.这可能对您的使用有好处
if(isChecked) {
for (int i = 0; i < fonts.size(); i++) {
if (i == position) continue;
Font f = fonts.get(i);
if (f.isSelected()) {
f.setSelected(false);
notifyItemChanged(i); // Tell the adapter this item is updated
}
}
fonts.get(position).setSelected(isChecked);
notifyItemChanged(position);
}
Run Code Online (Sandbox Code Playgroud)
Akl*_*ngh 12
这是它的样子
适配器内部
private int selectedPosition = -1;
Run Code Online (Sandbox Code Playgroud)
和 onBindViewHolder
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
if (selectedPosition == position) {
holder.itemView.setSelected(true); //using selector drawable
holder.tvText.setTextColor(ContextCompat.getColor(holder.tvText.getContext(),R.color.white));
} else {
holder.itemView.setSelected(false);
holder.tvText.setTextColor(ContextCompat.getColor(holder.tvText.getContext(),R.color.black));
}
holder.itemView.setOnClickListener(v -> {
if (selectedPosition >= 0)
notifyItemChanged(selectedPosition);
selectedPosition = holder.getAdapterPosition();
notifyItemChanged(selectedPosition);
});
}
Run Code Online (Sandbox Code Playgroud)
就是这样!如您所见,我只是在通知(更新)先前选择的项目和新选择的项目
我的 Drawable 将其设置为 recyclerview 子视图的背景
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/blue" />
</shape>
</item>
Run Code Online (Sandbox Code Playgroud)
小智 9
只需使用mCheckedPosition保存状态
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.checkBox.setChecked(position == mCheckedPostion);
holder.checkBox.setOnClickListener(v -> {
if (position == mCheckedPostion) {
holder.checkBox.setChecked(false);
mCheckedPostion = -1;
} else {
mCheckedPostion = position;
notifyDataSetChanged();
}
});
}
Run Code Online (Sandbox Code Playgroud)
这可能对那些想要单个无线电按钮工作的人有用 - > 单选按钮RecycleView - Gist
如果不支持lambda表达式,请改用:
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(mSelectedItem); // to update last selected item.
mSelectedItem = getAdapterPosition();
}
};
Run Code Online (Sandbox Code Playgroud)
干杯
您需要清除OnCheckedChangeListener之前的设置setChecked():
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mRadioButton.setOnCheckedChangeListener(null);
holder.mRadioButton.setChecked(position == mCheckedPosition);
holder.mRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mCheckedPosition = position;
notifyDataSetChanged();
}
});
}
Run Code Online (Sandbox Code Playgroud)
这样它就不会触发java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling错误.