In my application am displaying 20 multiple choice questions with the help of RecyclerView
.
If I change the value of first RadioGroup
and s
This problem occurs because of a bug in either RecyclerView
or somewhere in the Android SDK. Anyway, I took the advice from another SO question - onCheckedChanged called automatically.
For RadioGroup
, it will be a little different. There are two ways to go about. I recommend 1st one since it is plug-n-play.
set OnCheckedChangeListener
on RadioGroup
:
mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(checkedId == -1) {
Log.v("onCheck", "Android bug since RadioButton doesn't get unchecked normally!");
}
else {
Log.v("onCheck", "Valid click. By user");
mMyListObjectArr[position].setChecked(checkedId);
}
}
});
or set onCheckedChangeListener
on all RadioButton
s inside the RadioGroup
:
CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.isPressed()) {
Log.v("onCheck", position + ", valid click by user");
mMyListObjectArr[position].setChecked(buttonView.getId());
}
else {
Log.v("onCheck", "Android bug");
}
}
};
mRadioButton1.setOnCheckedChangeListener(onCheckedChangeListener);
mRadioButton2.setOnCheckedChangeListener(onCheckedChangeListener);
RecyclerView came over ListView and its major property that is It Reuses cells while scrolling up and down. Due to this it do not flick while scrolling even if you have lots of data in your list. You are getting problem due to Reuse of cells in RecyclerView.
You can overcome to this problem by binding your RecyclerView list data to Modal class with getter and setter method.
You can display checkbox
checked or unchecked on basis of cell position and corresponding data.
In my sample i used setOnClickListener
instead of setOnCheckedChangeListenerto
to show checkbox checked or unchecked.
I created a sample code that will work as per your req.
First we have to create the xml as follows :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerViewAppList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
Then we will create an interface as follows
public interface OnOptionSelected {
public void onOptionSelected(int position,int itemSelected);
}
Then we will create the model class as follows :
public class QuestionModel {
private String question;
private int seleectedAnswerPosition;
private boolean op1Sel,op2Sel,op3Sel; // options
public boolean isOp1Sel() {
return op1Sel;
}
public void setOp1Sel(boolean op1Sel) {
this.op1Sel = op1Sel;
if(op1Sel){ // To make sure only one option is selected at a time
setOp2Sel(false);
setOp3Sel(false);
}
}
public boolean isOp2Sel() {
return op2Sel;
}
public void setOp2Sel(boolean op2Sel) {
this.op2Sel = op2Sel;
if(op2Sel){
setOp1Sel(false);
setOp3Sel(false);
}
}
public boolean isOp3Sel() {
return op3Sel;
}
public void setOp3Sel(boolean op3Sel) {
this.op3Sel = op3Sel;
if(op3Sel){
setOp2Sel(false);
setOp1Sel(false);
}
}
public int getSeleectedAnswerPosition() {
return seleectedAnswerPosition;
}
public void setSeleectedAnswerPosition(int seleectedAnswerPosition) {
this.seleectedAnswerPosition = seleectedAnswerPosition;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
}
Then we will create the view for row :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/question"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton
android:id="@+id/radoptionOne"
android:text="May Be"
android:checked="false"
android:saveEnabled="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton
android:checked="false"
android:id="@+id/radoptionTwo"
android:text="NO"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton
android:checked="false"
android:id="@+id/radoptionThree"
android:text="Yes"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Adapter class as follows:
public class QuestionAdapter extends RecyclerView.Adapter<QuestionAdapter.ViewHolder> {
private List<QuestionModel> questionModels;
public void setOnOptionSelected(OnOptionSelected onOptionSelected) {
this.onOptionSelected = onOptionSelected;
}
private OnOptionSelected onOptionSelected;
public List<QuestionModel> getQuestionModels() {
return questionModels;
}
public void setQuestionModels(List<QuestionModel> questionModels) {
this.questionModels = questionModels;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView question;
RadioGroup radioGroup;
RadioButton op1, op2, op3;
ViewHolder(View view) {
super(view);
question = (TextView) view.findViewById(R.id.question);
//radioGroup=(RadioGroup)view.findViewById(R.id.radGroup);
op1 = (RadioButton) view.findViewById(R.id.radoptionOne);
op2 = (RadioButton) view.findViewById(R.id.radoptionTwo);
op3 = (RadioButton) view.findViewById(R.id.radoptionThree);
op1.setOnClickListener(this);
op2.setOnClickListener(this);
op3.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.radoptionOne:
onOptionSelected.onOptionSelected(getAdapterPosition(), 1);
break;
case R.id.radoptionTwo:
onOptionSelected.onOptionSelected(getAdapterPosition(), 2);
break;
case R.id.radoptionThree:
onOptionSelected.onOptionSelected(getAdapterPosition(), 3);
break;
}
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
// create a normal view
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_view, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
viewHolder.question.setText(questionModels.get(position).getQuestion());
Log.e("POSITION" + position, "1" + questionModels.get(position).isOp1Sel());
Log.e("POSITION" + position, "2" + questionModels.get(position).isOp2Sel());
Log.e("POSITION" + position, "3" + questionModels.get(position).isOp3Sel());
viewHolder.op1.setChecked(questionModels.get(position).isOp1Sel());
viewHolder.op2.setChecked(questionModels.get(position).isOp2Sel());
viewHolder.op3.setChecked(questionModels.get(position).isOp3Sel());
}
@Override
public int getItemCount() {
if (questionModels != null) {
return questionModels.size();
}
return 0;
}
}
Then the Activity class :
public class MainActivity extends Activity implements OnOptionSelected{
private RecyclerView mRecyclerView;
private List<QuestionModel> questionModels;
private QuestionAdapter questionAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView =(RecyclerView)findViewById(R.id.recyclerViewAppList);
mRecyclerView.setHasFixedSize(true);
questionModels=new ArrayList<QuestionModel>();
for (int i=0;i<20;i++)
{
QuestionModel questionModel=new QuestionModel();
questionModel.setQuestion("Question " + (i + 1));
questionModels.add(questionModel);
}
questionAdapter =new QuestionAdapter();
questionAdapter.setOnOptionSelected(this);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
questionAdapter.setQuestionModels(questionModels);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(questionAdapter);
}
@Override
public void onOptionSelected(int position, int itemSelected) {
questionModels.get(position).setSeleectedAnswerPosition(itemSelected);
switch (itemSelected){
case 1:
questionModels.get(position).setOp1Sel(true);
break;
case 2:
questionModels.get(position).setOp2Sel(true);
break;
case 3:
((QuestionModel)questionModels.get(position)).setOp3Sel(true);
break;
}
questionAdapter.setQuestionModels(questionModels);
questionAdapter.notifyDataSetChanged();
// mRecyclerView.setAdapter(questionAdapter);
}
}
I tried the solution with Radiogroup but it was not working properly( sometime it was retaining the old value). Then I changed the way of the selecting options in my model class.