How to use RadioGroup in ListView custom adapter?
This solution works and it's pretty clean, but there might be some better solutions out there.
You should use your adapter to manage the radio buttons state.
You must keep a reference to the last checked radio button, and then upon RadioButton.onClick
you set the last checked radio button setChecked(false)
.
also remember to set the newly selected radio button as the last selected radio button.
see example:
private class MyAdapter extends ArrayAdapter<String>{
private int mResourceId = 0;
private LayoutInflater mLayoutInflater;
private RadioButton mSelectedRB;
private int mSelectedPosition = -1;
public MyAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
mResourceId = resource;
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if(view == null){
view = mLayoutInflater.inflate(mResourceId, parent, false);
holder = new ViewHolder();
holder.name = (TextView)view.findViewById(R.id.text);
holder.radioBtn = (RadioButton)view.findViewById(R.id.radioButton1);
view.setTag(holder);
}else{
holder = (ViewHolder)view.getTag();
}
holder.radioBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(position != mSelectedPosition && mSelectedRB != null){
mSelectedRB.setChecked(false);
}
mSelectedPosition = position;
mSelectedRB = (RadioButton)v;
}
});
if(mSelectedPosition != position){
holder.radioBtn.setChecked(false);
}else{
holder.radioBtn.setChecked(true);
if(mSelectedRB != null && holder.radioBtn != mSelectedRB){
mSelectedRB = holder.radioBtn;
}
}
holder.name.setText(getItem(position));
return view;
}
private class ViewHolder{
TextView name;
RadioButton radioBtn;
}
}
Hope it does it for you.
You need to do two things:
- Use
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- Make your custom row view implement
Checkable
. (More info about this here).
This is my solution. Its pretty easy.
my_radio_adapter_item.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
... />
<RadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
... />
</LinearLayout>
MyRadioAdapter.java
public class MyRadioAdapter extends BaseAdapter
{
private Context mContext;
private ArrayList<Variation> mVariations;
private int mSelectedVariation;
public MyRadioAdapter(Context context, ArrayList<Variation> variations, int selectedVariation)
{
mContext = context;
mVariations = variations;
mSelectedVariation = selectedVariation;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
View view = convertView;
if(view==null)
{
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.my_radio_adapter_item, null);
}
final Variation variation = mVariations.get(position);
TextView name = (TextView) view.findViewById(R.id.name);
RadioButton radio = (RadioButton) view.findViewById(R.id.radio);
name.setText(variation.getName());
if(position==mSelectedVariation) radio.setChecked(true);
else radio.setChecked(false);
view.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
mSelectedVariation = position;
MyRadioAdapter.this.notifyDataSetChanged();
}
});
return view;
}
...
}
You could put a
private int selectedIndex = -1;
then, in the getView-code you could check
if (position == selectedIndex) {
rbtn.setSelected ( true );
}
else {
rbtn.setSelected ( false );
}
and add a method in your custom adapter:
public void setSelectedIndex(int index) {
//some range-checks, maybe
selectedIndex = index;
//invalidate
}
Then, in your onItemClickedListener you call setSelectedIndex on the position.