我知道在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);
}
}
});
}
尝试此代码时,我得到了预期的输出,但完全没有。
我将用图片解释这个。
默认情况下,从我的适配器中选择第一项
然后我试图选择第二个然后是第三个,然后是第四个,最后是第五个,
此处仅应选择第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)
答案 0 :(得分:87)
问题的解决方案:
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);
}
});
}
... ...
}
希望这有帮助!
答案 1 :(得分:68)
它太迟了仍然发布它可能对其他人有帮助 使用以下代码作为参考来检查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();
}
});
}
}
}
答案 2 :(得分:12)
看起来有两件事在这里发挥作用:
我将分别解决每个问题。
基本上,在onBindViewHolder
中,您会获得一个已初始化的ViewHolder
,其中已包含视图。 ViewHolder
之前可能已经或可能没有绑定某些数据了!
请注意这段代码:
holder.checkBox.setChecked(fonts.get(position).isSelected());
如果持有者先前已被绑定,则复选框已经有一个监听器,用于检查状态是否发生变化!此时正在触发该侦听器,这正是导致您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);
}
答案 3 :(得分:8)
只需使用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();
}
});
}
答案 4 :(得分:8)
对于那些想要使用单个无线电按钮工作的人来说,这可能会有所帮助 - &gt; Radio Button RecycleView - Gist
如果不支持lambda表达式,请改用:
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(mSelectedItem); // to update last selected item.
mSelectedItem = getAdapterPosition();
}
};
干杯
答案 5 :(得分:7)
在设置HashMap<String,String> map = new Gson().fromJson( yourJsonString, new TypeToken<HashMap<String, String>>(){}.getType());
:
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();
}
});
}
错误。
答案 6 :(得分:3)
这是它的外观
在适配器内部
private int selectedPosition = -1;
和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);
});
}
就这样! 如您所见,我只是通知(更新)先前选择的项目和新选择的项目
我的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>
答案 7 :(得分:2)
public class GetStudentAdapter extends
RecyclerView.Adapter<GetStudentAdapter.MyViewHolder> {
private List<GetStudentModel> getStudentList;
Context context;
RecyclerView recyclerView;
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView textStudentName;
RadioButton rbSelect;
public MyViewHolder(View view) {
super(view);
textStudentName = (TextView) view.findViewById(R.id.textStudentName);
rbSelect = (RadioButton) view.findViewById(R.id.rbSelect);
}
}
public GetStudentAdapter(Context context, RecyclerView recyclerView, List<GetStudentModel> getStudentList) {
this.getStudentList = getStudentList;
this.recyclerView = recyclerView;
this.context = context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.select_student_list_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.textStudentName.setText(getStudentList.get(position).getName());
holder.rbSelect.setChecked(getStudentList.get(position).isSelected());
holder.rbSelect.setTag(position); // This line is important.
holder.rbSelect.setOnClickListener(onStateChangedListener(holder.rbSelect, position));
}
@Override
public int getItemCount() {
return getStudentList.size();
}
private View.OnClickListener onStateChangedListener(final RadioButton checkBox, final int position) {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkBox.isChecked()) {
for (int i = 0; i < getStudentList.size(); i++) {
getStudentList.get(i).setSelected(false);
}
getStudentList.get(position).setSelected(checkBox.isChecked());
notifyDataSetChanged();
} else {
}
}
};
}
}
答案 8 :(得分:1)
以下内容可能对 RecyclerView with Single Choice 有帮助。
这样做的三个步骤, 1)声明一个全局整数变量
private int mSelectedItem = -1;
2)在onBindViewHolder
mRadio.setChecked(position == mSelectedItem);
3)在onClickListener
mSelectedItem = getAdapterPosition();
notifyItemRangeChanged(0, mSingleCheckList.size());
mAdapter.onItemHolderClick(SingleCheckViewHolder.this);
答案 9 :(得分:1)
这是因为RecyclerView,顾名思义,在回收其ViewHolders方面做得很好。这意味着每个ViewHolder,当它离开视线时(实际上,它需要的不仅仅是看不见,但是以这种方式简化它是有意义的),它被回收;这意味着RecyclerView使用已经膨胀的ViewHolder,并用数据集中另一个项目的元素替换它的元素。
现在,这里发生的事情是,一旦向下滚动并且您选择的第一个ViewHolders不在视线范围内,它们将被回收并用于数据集的其他位置。再次上升后,绑定到前5个项的ViewHolders现在不一定相同,现在。
这就是为什么你应该在你的适配器中保留内部变量来记住每个项目的选择状态。这样,在onBindViewHolder
方法中,您可以知道ViewHolder当前被绑定的项目是否被选中,并相应地修改View,在这种情况下是您的RadioButton的状态(尽管我建议使用CheckBox)如果你打算选择多个项目。)
如果您想了解有关RecyclerView及其内部工作的更多信息,请邀请您查看我在GitHub上开始的FancyAdapters项目。它是一组适配器,用于实现选择,拖放元素和滑动以关闭功能。也许通过检查代码,您可以很好地理解RecyclerView的工作原理。
答案 10 :(得分:1)
这个简单的对我有用
private RadioButton lastCheckedRB = null;
...
@Override
public void onBindViewHolder(final CoachListViewHolder holder, final int position) {
holder.priceRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton checked_rb = (RadioButton) group.findViewById(checkedId);
if (lastCheckedRB != null) {
lastCheckedRB.setChecked(false);
}
//store the clicked radiobutton
lastCheckedRB = checked_rb;
}
});
答案 11 :(得分:1)
我想分享我所取得的类似成就,可能会对某人有所帮助。
下面的代码来自应用程序,以从cardview(cvAddress)
中显示的地址列表中选择一个地址,以便在点击特定item(cardview)
时,项目内的imageView
应设置为不同的资源(选择/取消选择)
@Override
public void onBindViewHolder(final AddressHolder holder, final int position)
{
holderList.add(holder);
holder.tvAddress.setText(addresses.get(position).getAddress());
holder.cvAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectCurrItem(position);
}
});
}
private void selectCurrItem(int position)
{
int size = holderList.size();
for(int i = 0; i<size; i++)
{
if(i==position)
holderList.get(i).ivSelect.setImageResource(R.drawable.select);
else
holderList.get(i).ivSelect.setImageResource(R.drawable.unselect);
}
}
我不知道这是最好的解决方案,但这对我有用。
答案 12 :(得分:1)
这是Adapter类的外观:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewHolder>{
Context context;
ArrayList<RouteDetailsFromFirestore> routeDetailsFromFirestoreArrayList_;
public int lastSelectedPosition=-1;
public MyRecyclerViewAdapter(Context context, ArrayList<RouteDetailsFromFirestore> routeDetailsFromFirestoreArrayList)
{
this.context = context;
this.routeDetailsFromFirestoreArrayList_ = routeDetailsFromFirestoreArrayList;
}
@NonNull
@Override
public MyRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i)
{
// LayoutInflater layoutInflater = LayoutInflater.from(mainActivity_.getBaseContext());
LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
View view = layoutInflater.inflate(R.layout.route_details, viewGroup, false);
return new MyRecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final MyRecyclerViewHolder myRecyclerViewHolder, final int i) {
/* This is the part where the appropriate checking and unchecking of radio button happens appropriately */
myRecyclerViewHolder.mRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b) {
if (lastSelectedPosition != -1) {
/* Getting the reference to the previously checked radio button and then unchecking it.lastSelectedPosition has the index of the previously selected radioButton */
//RadioButton rb = (RadioButton) ((MainActivity) context).linearLayoutManager.getChildAt(lastSelectedPosition).findViewById(R.id.rbRadioButton);
RadioButton rb = (RadioButton) ((MainActivity) myRecyclerViewHolder.mRadioButton.getContext()).linearLayoutManager.getChildAt(lastSelectedPosition).findViewById(R.id.rbRadioButton);
rb.setChecked(false);
}
lastSelectedPosition = i;
/* Checking the currently selected radio button */
myRecyclerViewHolder.mRadioButton.setChecked(true);
}
}
});
}
@Override
public int getItemCount() {
return routeDetailsFromFirestoreArrayList_.size();
}
} // End of Adapter Class
在MainActivity.java内部,我们这样称呼Adapter类的ctor。传递给Adapter ctor的上下文是MainActivity:
myRecyclerViewAdapter = new MyRecyclerViewAdapter(MainActivity.this, routeDetailsList);
答案 13 :(得分:0)
public class LastTransactionAdapter extends RecyclerView.Adapter<LastTransactionAdapter.MyViewHolder> {
private Context context;
private List<PPCTransaction> ppcTransactionList;
private static int checkedPosition = -1;
public LastTransactionAdapter(Context context, List<PPCTransaction> ppcTransactionList) {
this.context = context;
this.ppcTransactionList = ppcTransactionList;
}
@NonNull
@Override
public LastTransactionAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.last_transaction_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull LastTransactionAdapter.MyViewHolder holder, int position) {
holder.setLastTransaction(ppcTransactionList.get(position), position);
}
@Override
public int getItemCount() {
return ppcTransactionList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private LinearLayout linTransactionItem;
private RadioButton radioButton;
private TextView tvDate, tvMerchantName, tvAmount, tvStatus;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
linTransactionItem = itemView.findViewById(R.id.linTransactionItem);
tvDate = itemView.findViewById(R.id.tvDate);
tvMerchantName = itemView.findViewById(R.id.tvMerchantName);
tvAmount = itemView.findViewById(R.id.tvAmount);
tvStatus = itemView.findViewById(R.id.tvStatus);
radioButton = itemView.findViewById(R.id.radioButton);
}
public void setLastTransaction(PPCTransaction ppcTransaction, int position) {
tvDate.setText(ppcTransaction.getmDate());
tvMerchantName.setText(ppcTransaction.getmMerchantName());
tvAmount.setText(ppcTransaction.getmAmount());
tvStatus.setText(ppcTransaction.getmStatus());
if (checkedPosition == -1) {
radioButton.setChecked(false);
} else {
if (checkedPosition == getAdapterPosition()) {
radioButton.setChecked(true);
} else {
radioButton.setChecked(false);
}
}
linTransactionItem.setOnClickListener(v -> {
radioButton.setChecked(true);
if (checkedPosition != getAdapterPosition()) {
notifyItemChanged(checkedPosition);
checkedPosition = getAdapterPosition();
}
});
}
}
答案 14 :(得分:0)
因此,在花了很多天之后,这才是我想出的对我有用的方法,也是良好实践,
代码
@Override
public void onTicketSelect(int position) {
for (ListType listName : list) {
listName.setmSelectedConstant(0);
}
8。在此之外,使所选位置常数为1:
代码
list.get(position).setmSelectedConstant(1);
adapter.notifyDataSetChanged();
通知此更改。代码
if (listVarInAdapter.get(position).getmSelectedConstant() == 1) {
holder.checkIcon.setChecked(true);
selectedTicketType = dataSetList.get(position);}
else {
commonHolder.checkCircularIcon.setChecked(false);
}
答案 15 :(得分:0)
请试试这个...... 这对我有用..
在适配器中,取一个稀疏的布尔数组。
SparseBooleanArray sparseBooleanArray;
在构造函数中初始化它,
sparseBooleanArray=new SparseBooleanArray();
在bind holder add中,
@Override
public void onBindViewHolder(DispositionViewHolder holder, final int position) {
holder.tv_disposition.setText(dispList.get(position).getName());
if(sparseBooleanArray.get(position,false))
{
holder.rd_disp.setChecked(true);
}
else
{
holder.rd_disp.setChecked(false);
}
setClickListner(holder,position);
}
private void setClickListner(final DispositionViewHolder holder, final int position) {
holder.rd_disp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sparseBooleanArray.clear();
sparseBooleanArray.put(position, true);
notifyDataSetChanged();
}
});
}
rd_disp是xml文件中的单选按钮。
因此当recycleler视图加载项时,在bindView Holder中检查sparseBooleanArray是否包含值&#34; true&#34;与其立场相对应。
如果返回的值为true,那么我们将单选按钮选择设置为true.Else 我们将选择设置为false。 在onclickHolder中,我清除了sparseArray并将值设置为对应于该位置的值。 当我调用notify datasetChange时,它再次调用onBindViewHolder并再次检查条件。这使我们的选择仅选择特定的无线电。
答案 16 :(得分:-1)
你是不是很复杂?
SharedPreferences sharedPreferences =getSharedPreferences("appdetails",MODE_PRIVATE);
String selection=sharedPreferences.getString("selection", null);
public void onBindViewHolder(ViewHolder holder, final int position) {
String name=fonts.get(position).getName();
holder.mTextView.setText(name);
if(selection.equals(name)){
holder.checkBox.setChecked(false); //
holder.checkBox.setChecked(true);
}
holder.checkbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences sharedPreferences = getSharedPreferences("appdetails", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("selection", name);
r.setChecked(false);
editor.apply();
holder.checkBox.setChecked(true);
}
});
}
答案 17 :(得分:-1)
我会告诉你我是怎么做的,而且效果很好。以上答案都不适合我。
所以我制作了我的自定义单选按钮。还不要惊慌。它很容易。 只需制作一个空的可绘制圆圈,然后制作一个填充的可绘制圆圈。
现在使用 2 个视图,一个带有空的 drawable,一个带有填充的 drawable。补一个gone
。
现在在适配器中这样玩。
RecyclerView 的 BindViewHolder
@Override
public void onBindViewHolder(@NonNull @NotNull SubscriptionAdapter.Viewholder holder, int i) {
if (selectedView != null) selectedView.setVisibility(View.VISIBLE);
if (lastSelectedView != null) lastSelectedView.setVisibility(View.GONE);
holder.viewEmpty.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (subscriptionList.get(i).isSelected()) {
Log.d(Constants.TAG, "set selected - false");
subscriptionList.get(i).setSelected(false);
} else {
Log.d(Constants.TAG, "set selected - true");
subscriptionList.get(i).setSelected(true);
if (selectedView != null) lastSelectedView = selectedView;
selectedView = holder.viewFill;
}
notifyDataSetChanged();
}
});
}