检查单选按钮回收
Checked RadioButton Recycling
我正在以编程方式将无线电组添加到我的 recyclerview,它工作正常。
但是当我检查它并滚动 recyclerview 时,它会丢失已检查的收音机。
我看过很多解决方法和例子,但是我无法实现。已经连续几天了。
我将选中的收音机保存在模型中,您可以在下面的代码中看到。
适配器:
@Override
public void onBindViewHolder(final NROptionLineHolder holder, int position) {
holder.priceGroup.removeAllViews();
holder.priceGroup.setOnCheckedChangeListener(null);
int id = (position+1)*100;
checklistModel = mChecklists.get(position);
holder.packageName.setText(checklistModel.getTitle());
for(String price : checklistModel.getQuestions()){
RadioButton rb = new RadioButton(NROptionLineAdapter.this.context);
rb.setId(id++);
rb.setText(price);
holder.priceGroup.addView(rb);
}
holder.priceGroup.check(checklistModel.getSelectedId());
holder.priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
}
持有人
OnNROptionListener onNROptionListener;
public NROptionLineHolder(View itemView, OnNROptionListener onNROptionListener) {
super(itemView);
packageName = itemView.findViewById(R.id.package_name);
priceGroup = itemView.findViewById(R.id.price_grp);
// priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
// @Override
// public void onCheckedChanged(RadioGroup radioGroup, int i) {
//
// Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
// }
// });
this.onNROptionListener = onNROptionListener;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
onNROptionListener.onNROptionClick(getAdapterPosition());
}
public interface OnNROptionListener {
void onNROptionClick(int position);
}
}
编辑 1 - 广播组
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RadioGroup
android:id="@+id/price_grp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/package_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:orientation="horizontal"/>
</android.support.constraint.ConstraintLayout>
编辑 2
根据要求,这是我的 ChecklistActivity
中的重要代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checklist);
intent = getIntent();
size = intent.getIntExtra("size", 0);
nr = intent.getIntExtra("nr", 0);
Log.d(TAG, "Checklist Activity - Qtd Questões: " + size);
Log.d(TAG, "Checklist Activity - NR: " + nr);
btnSaveCheck = findViewById(R.id.btnSaveChecklist);
mRecyclerView = findViewById(R.id.package_lst);
setupRecycler();
btnSaveCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Sucesso", Toast.LENGTH_SHORT).show();
}
});
}
private void setupRecycler() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
setupList();
mAdapter = new NROptionLineAdapter(data, this, getApplication());
mRecyclerView.setAdapter(mAdapter);
}
private void setupList(){
data = new ArrayList<>();
class setupList extends AsyncTask<Void, Void, List<MRNrOption>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<MRNrOption> doInBackground(Void... voids) {
list = DatabaseClient
.getInstance(getApplicationContext())
.getAppDatabase()
.mrNrOptionDAO()
.loadAllByNRId(nr);
return list;
}
@Override
protected void onPostExecute(List<MRNrOption> list) {
super.onPostExecute(list);
List<String> priceList = new ArrayList<>();
priceList.add("Sim");
priceList.add("Não");
priceList.add("Não se Aplica");
for (int i=0; i<list.size(); i++) {
Log.d(TAG, "NRs Activity - Adding To List: " + list.get(i).getTitle());
data.add(new Checklist(
list.get(i).getTitle(),
priceList)
);
mAdapter.notifyDataSetChanged();
}
}
}
setupList lm = new setupList();
lm.execute();
}
编辑 3 - 重要
RadioGroups 和 RadioButtons 是以编程方式生成的,因为我从服务器获取所有问题,问题的数量根据用户之前的选择而不同,这就是我需要这种方式的原因。
编辑 4
GIF to enhance the problem visualization
编辑 5 - 清单模型 Class
public class Checklist {
String title;
List<String> questions;
boolean isRadioButtonAdded;
int selectedId;
public Checklist(String title, List<String> questions) {
this.title = title;
this.questions = questions;
}
public Checklist(){}
public boolean getIsAdded(){
return isRadioButtonAdded;
}
public void setIsAdded(boolean isAdded){
this.isRadioButtonAdded = isAdded;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getQuestions() {
return questions;
}
public void setQuestions(List<String> questions) {
this.questions = questions;
}
public int getSelectedId() {
return selectedId;
}
public void setSelectedId(int selectedId) {
this.selectedId = selectedId;
}
}
当 onClick 事件发生时,将单选按钮的选中/未选中状态保存到您的模型中(即您在列表中的项目应该有一个字段)。当您绑定 ViewHolder 时,请确保将复选框的值设置为您在模型中保存的值。
下面的代码怎么样?
适配器:
由于视图被回收,我以为唯一id是个错误。
int id = (position+1)*100;
至
int id = 1;
唯一可行的解决方案是在 ViewHolder 中将 RecyclerView 设置为不可回收。
this.setIsRecyclable(false);
虽然我不确定这是否会解决您的问题,但作为优化也是一个好的做法,您应该将听众附加到 onCreateViewHolder
而不是 onBindViewHolder
这个防止为侦听器创建多个对象。
你为什么不把这段代码移到 onCreateViewHolder
你拥有的视图持有者中的这个块:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
尝试将您的 setOnCheckedChangeListener
代码移动到 ViewHolder 并在此处更新您的 mCheckList
:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
mCheckList.get(getAdapterPosition()).setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
}});
主要问题是您没有更新正确的项目状态。当您单击单选按钮时,它将仅更新调用的最后一项 onBindViewHolder
,因为 checklistModel 仅包含最后一个参考。要解决此问题,您始终需要在侦听器中访问 mainList。
recyclerview 的工作方式是,当您向下或向上滚动直到视图不可见时,它会存储状态,但是当您向下滚动 recyclerview 或向上滚动 recyclerview 时,它会销毁该行并放置一个新行position.so 整行的视图将被破坏。
问题的解决方案是将另一个变量添加到您正在使用的列表中,当单选按钮改变状态时,您存储数据并继续。
在你的数据模型中像这样 class
在 Model Class 中定义 recyclerview 使用的列表。
Boolean is stateclicked;
int state position;
并且在 OnBindViewholder 中您可以获取此数据的值。如果该值为 null 那么它就不会被点击,如果它被点击那么你将布尔值更改为 yes 并将状态的值放入整数
我正在以编程方式将无线电组添加到我的 recyclerview,它工作正常。 但是当我检查它并滚动 recyclerview 时,它会丢失已检查的收音机。
我看过很多解决方法和例子,但是我无法实现。已经连续几天了。
我将选中的收音机保存在模型中,您可以在下面的代码中看到。
适配器:
@Override
public void onBindViewHolder(final NROptionLineHolder holder, int position) {
holder.priceGroup.removeAllViews();
holder.priceGroup.setOnCheckedChangeListener(null);
int id = (position+1)*100;
checklistModel = mChecklists.get(position);
holder.packageName.setText(checklistModel.getTitle());
for(String price : checklistModel.getQuestions()){
RadioButton rb = new RadioButton(NROptionLineAdapter.this.context);
rb.setId(id++);
rb.setText(price);
holder.priceGroup.addView(rb);
}
holder.priceGroup.check(checklistModel.getSelectedId());
holder.priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
}
持有人
OnNROptionListener onNROptionListener;
public NROptionLineHolder(View itemView, OnNROptionListener onNROptionListener) {
super(itemView);
packageName = itemView.findViewById(R.id.package_name);
priceGroup = itemView.findViewById(R.id.price_grp);
// priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
// @Override
// public void onCheckedChanged(RadioGroup radioGroup, int i) {
//
// Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
// }
// });
this.onNROptionListener = onNROptionListener;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
onNROptionListener.onNROptionClick(getAdapterPosition());
}
public interface OnNROptionListener {
void onNROptionClick(int position);
}
}
编辑 1 - 广播组
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RadioGroup
android:id="@+id/price_grp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/package_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:orientation="horizontal"/>
</android.support.constraint.ConstraintLayout>
编辑 2
根据要求,这是我的 ChecklistActivity
中的重要代码@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checklist);
intent = getIntent();
size = intent.getIntExtra("size", 0);
nr = intent.getIntExtra("nr", 0);
Log.d(TAG, "Checklist Activity - Qtd Questões: " + size);
Log.d(TAG, "Checklist Activity - NR: " + nr);
btnSaveCheck = findViewById(R.id.btnSaveChecklist);
mRecyclerView = findViewById(R.id.package_lst);
setupRecycler();
btnSaveCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Sucesso", Toast.LENGTH_SHORT).show();
}
});
}
private void setupRecycler() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
setupList();
mAdapter = new NROptionLineAdapter(data, this, getApplication());
mRecyclerView.setAdapter(mAdapter);
}
private void setupList(){
data = new ArrayList<>();
class setupList extends AsyncTask<Void, Void, List<MRNrOption>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<MRNrOption> doInBackground(Void... voids) {
list = DatabaseClient
.getInstance(getApplicationContext())
.getAppDatabase()
.mrNrOptionDAO()
.loadAllByNRId(nr);
return list;
}
@Override
protected void onPostExecute(List<MRNrOption> list) {
super.onPostExecute(list);
List<String> priceList = new ArrayList<>();
priceList.add("Sim");
priceList.add("Não");
priceList.add("Não se Aplica");
for (int i=0; i<list.size(); i++) {
Log.d(TAG, "NRs Activity - Adding To List: " + list.get(i).getTitle());
data.add(new Checklist(
list.get(i).getTitle(),
priceList)
);
mAdapter.notifyDataSetChanged();
}
}
}
setupList lm = new setupList();
lm.execute();
}
编辑 3 - 重要
RadioGroups 和 RadioButtons 是以编程方式生成的,因为我从服务器获取所有问题,问题的数量根据用户之前的选择而不同,这就是我需要这种方式的原因。
编辑 4
GIF to enhance the problem visualization
编辑 5 - 清单模型 Class
public class Checklist {
String title;
List<String> questions;
boolean isRadioButtonAdded;
int selectedId;
public Checklist(String title, List<String> questions) {
this.title = title;
this.questions = questions;
}
public Checklist(){}
public boolean getIsAdded(){
return isRadioButtonAdded;
}
public void setIsAdded(boolean isAdded){
this.isRadioButtonAdded = isAdded;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getQuestions() {
return questions;
}
public void setQuestions(List<String> questions) {
this.questions = questions;
}
public int getSelectedId() {
return selectedId;
}
public void setSelectedId(int selectedId) {
this.selectedId = selectedId;
}
}
当 onClick 事件发生时,将单选按钮的选中/未选中状态保存到您的模型中(即您在列表中的项目应该有一个字段)。当您绑定 ViewHolder 时,请确保将复选框的值设置为您在模型中保存的值。
下面的代码怎么样?
适配器:
由于视图被回收,我以为唯一id是个错误。
int id = (position+1)*100;
至
int id = 1;
唯一可行的解决方案是在 ViewHolder 中将 RecyclerView 设置为不可回收。
this.setIsRecyclable(false);
虽然我不确定这是否会解决您的问题,但作为优化也是一个好的做法,您应该将听众附加到 onCreateViewHolder
而不是 onBindViewHolder
这个防止为侦听器创建多个对象。
你为什么不把这段代码移到 onCreateViewHolder
你拥有的视图持有者中的这个块:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
尝试将您的 setOnCheckedChangeListener
代码移动到 ViewHolder 并在此处更新您的 mCheckList
:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
mCheckList.get(getAdapterPosition()).setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
}});
主要问题是您没有更新正确的项目状态。当您单击单选按钮时,它将仅更新调用的最后一项 onBindViewHolder
,因为 checklistModel 仅包含最后一个参考。要解决此问题,您始终需要在侦听器中访问 mainList。
recyclerview 的工作方式是,当您向下或向上滚动直到视图不可见时,它会存储状态,但是当您向下滚动 recyclerview 或向上滚动 recyclerview 时,它会销毁该行并放置一个新行position.so 整行的视图将被破坏。
问题的解决方案是将另一个变量添加到您正在使用的列表中,当单选按钮改变状态时,您存储数据并继续。 在你的数据模型中像这样 class 在 Model Class 中定义 recyclerview 使用的列表。
Boolean is stateclicked;
int state position;
并且在 OnBindViewholder 中您可以获取此数据的值。如果该值为 null 那么它就不会被点击,如果它被点击那么你将布尔值更改为 yes 并将状态的值放入整数