How to use RadioGroup in ListView custom adapter?
Asked Answered
M

8

45

I want to show a single select option in my list. I am using RadioButton in my listView row. I know that RadioGroup is used for single selection.

But problem is that I have added the RadioButton in my ListRowView. Now I want to add all my list items in one RadioButton. I am using Custom Adapter and in getView(). I get the RadioButton in getView(), but when want to add it in RadioGroup it say

"view already have parent , call removeView() in parent before"

And I know its true, but if I remove it from the view. Then it is not visible.

I also try to create and add RadioButton programmatically. And then add it in RadioGrop. And then to view of list row. But this time as the parent is RadioGroup, so again it say

"view already have parent , call removeView() in parent before"

What I want to do is to select only one item in list at a time. My code is as follows.

getView

 public class MyAdapter extends ArrayAdapter < MyMenuItem > {
    
    private LayoutInflater mInflater ;
    
    int                    mResource ;
    List < MyMenuItem >    mData ;
    Context context;
    
    public MyAdapter ( Context context , int resource , int textViewResourceId , List < MyMenuItem > data ) {
        super ( context , resource , textViewResourceId , data ) ;
        this.context = context;
        mData = data ;
        mResource = resource ;
        mInflater = ( LayoutInflater ) getSystemService ( Context.LAYOUT_INFLATER_SERVICE ) ;
    }
    
    @ Override
    public View getView ( int position , View convertView , ViewGroup parent ) {
        ViewHolder holder = null ;
        if ( convertView == null ) {
            convertView = mInflater.inflate ( mResource , null ) ;
            holder = new ViewHolder ( ) ;
            holder.icon = ( ImageView ) convertView.findViewById ( R.id.icon ) ;
            holder.text = ( TextView ) convertView.findViewById ( R.id.text ) ;
            holder.comment = ( TextView ) convertView.findViewById ( R.id.comment ) ;
            LinearLayout lin = ( LinearLayout ) convertView.findViewById ( R.id.linerList ) ;
            RadioButton rbtn = new RadioButton ( context );
            LayoutParams lparam = new LayoutParams ( LayoutParams.WRAP_CONTENT , LayoutParams.WRAP_CONTENT );
            rbtn.setSelected ( false );
            holder.check = rbtn;
            //radioGroup.addView ( rbtn );
            lin.addView ( rbtn , 0 );
            
            convertView.setTag ( holder ) ;
        } else {
            holder = ( ViewHolder ) convertView.getTag ( ) ;
        }
        
        holder.text.setText ( mData.get ( position ).getText ( ) ) ;
        holder.comment.setText ( mData.get ( position ).getComment ( ) ) ;
        
        holder.icon.setImageResource ( getApplicationContext ( ).getResources ( ).getIdentifier ( mData.get ( position ).getIcon ( ) ,
                "drawable" , getPackageName ( ) )

        ) ;
        
        return convertView ;
    }
    
}

My XML for the row

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<LinearLayout
    android:id = "@+id/linerList"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="6dip" />
</LinearLayout>
<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_weight="1"
    android:layout_height="fill_parent">
    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:text="My Application"
        android:textSize="20sp"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:textColor="@color/white" />
    <TextView
        android:id="@+id/comment"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:text="Simple application that shows how to use RelativeLayout"
        android:textSize="14sp"
        android:textColor="@color/light_gray" />
</LinearLayout>

It look like this if I not use RadioGroup

Meill answered 7/9, 2011 at 6:44 Comment(0)
S
46

You need to do two things:

  1. Use mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. Make your custom row view implement Checkable. (More info about this here).
Selfwill answered 14/9, 2011 at 23:25 Comment(3)
So there is not way to use Radio Group. But to write custom view for such a case. I was expecting the same. Thanks for your time. :)Meill
@Arslan: Yep, in your case you just need to extend LinearLayout, implement the Checkable interface and those methods will return your RadioButton implementation.Selfwill
Is there somewhere I can find a complete example of how to have radio button in custom adaptor and always only have one checked? I have searched very hard.Fusain
G
39

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.

Geoff answered 14/9, 2011 at 23:21 Comment(4)
@inistel It's working, but I have a "confirmation page" that shows the selected radio and have the option to return to the previous page. The problem is, when I select again another radio it's not working anymore. There are already two chosen radios.Mhd
this works for me at first time click,when i clicked second time the same button ,not workingBetray
nice solution saved my dayFlotow
If you use radio group you must remove it . When you removed radio group it will be fixRemy
N
15

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;
    }

    ...
}
Notum answered 13/5, 2012 at 14:36 Comment(4)
List view is referenced in some fragment or activity and it use just this adapter.Notum
You did not get the problem. When you will add item to listview then you will not allow to add it into radio group and vice verse.Meill
I think it's a bit rough and not efficient, but it helped me as a quick solution +1Nitroso
Could you pls tell me, what if you have several Radiobuttons horizontal, how to manage then?Jaw
G
2

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.

Gae answered 14/9, 2011 at 12:57 Comment(1)
I have try this to. But issue is then getView() call itself multiple times.(To measure width,height). For me it call multiple times. and if I select 2nd row. Then it show the opposite row(from the bottom in the list) not from top. :(Meill
A
1

You need to use the CheckedTextView instead of the normal one. http://developer.android.com/reference/android/widget/CheckedTextView.html

I never used it, but the AlertDialog uses it for the SingleChoice items. So it definitively will work :)

Edit: don't forget to call

 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Aspersorium answered 9/9, 2011 at 19:18 Comment(4)
I have check this already. Its fine. But It not give me the above view. But only textview with a checkbox. I am not using this. I need to do this using above view.Meill
I think it looks better if you have the radio buttons on the right side. And I also would use drawableLeft for the TextView and not an extra ImageView. Is my opinion :)Aspersorium
@Arslan: Using CheckedTextView will work since it implements Checkable, you need your custom view to implement that interface.Selfwill
Look at the AlertDialog source and the setSingleChoiceItems()Aspersorium
M
0

to add to the answers already given, for a more modular approach, have all list items inherit from the same class/interface that have a message function that would allow you to pass massages to them via the adapter.
The adapter registers itself with every item that is added to it, so every list item can call the adapter to send a message. then, in the RadioButton listener you can send a message to all the other radio buttons to turn off, turn the pressed one on, then finally notify dataset changed on the adapter.

I have an ListAdapter class, and a ListItem abstract class that are fairly robust; I'll send to anyone who needs it.
Multiple list item types supported.

Mccullers answered 28/7, 2016 at 2:17 Comment(0)
D
0

You can try this solution. Define a variable to get the currently selected position and do the following inside the custom adapter.

 singleRadio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            checkedButtonPosition = position;
  notifyDataSetChanged();
        }
    });

    if (checkedButtonPosition == position){
        singleRadio.setChecked(true);
    }else {
        singleRadio.setChecked(false);
    }
Dyslogia answered 7/4, 2020 at 18:0 Comment(0)
R
-1

you need the same output or different...

What i mean is you have select only one of the language from the list. Is it right?

conform it. So that i will give one example for that

Refugia answered 9/9, 2011 at 13:11 Comment(3)
You should comment instead of answer. I want to chose one at a time. I know this can be done via some other way. Temporarily I am doing some other way. But this this is what I really need to know that "How to use RadioGroup in ListView custom adapter?"Meill
then we did not use radio group for the list activity. We will use some properties for the default list like setchoicemode. But using this you did not customize the viewRefugia
Yes I know We can use customize list. But this will not look like the above image. I am doing this in some other manner.Meill

© 2022 - 2024 — McMap. All rights reserved.