web-dev-qa-db-fra.com

Comment utiliser RadioGroup dans l'adaptateur personnalisé ListView?

Je souhaite afficher une seule option de sélection dans ma liste. J'utilise RadioButton dans ma rangée listView. Je sais que RadioGroup est utilisé pour une sélection unique. 

Mais le problème est que j'ai ajouté la RadioButton dans ma ListRowView. Maintenant, je veux ajouter tous les éléments de ma liste dans une RadioButton. J'utilise Custom Adapter et dans getView(). Je reçois la RadioButton dans getView(), mais quand je veux l’ajouter dans RadioGroup il est dit 

"la vue a déjà un parent, appelez removeView () dans le parent avant"

Et je sais que c'est vrai, mais si je le retire de la vue. Alors ce n'est pas visible.

J'essaie également de créer et d'ajouter RadioButton par programme. Et puis ajoutez-le dans RadioGrop. Et puis pour voir la rangée de la liste. Mais cette fois en tant que parent est RadioGroup, donc encore une fois, il dit

"la vue a déjà un parent, appelez removeView () dans le parent avant"

Ce que je veux faire est de sélectionner un seul élément de la liste à la fois. Mon code est comme suit.

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

}

Mon XML pour la ligne

<?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

38
Arslan

Vous devez faire deux choses:

  1. Utilisez mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. Faites en sorte que votre vue de rangée personnalisée implémente Checkable. (Plus d'infos sur ce ici ).
46
Macarse

Cette solution fonctionne et elle est assez propre, mais il existe peut-être de meilleures solutions.

Vous devez utiliser votre adaptateur pour gérer l'état des boutons radio.

Vous devez conserver une référence au dernier bouton radio coché, puis sur RadioButton.onClick vous définissez le dernier bouton radio coché setChecked(false)

n'oubliez pas également de définir le bouton radio nouvellement sélectionné comme dernier bouton radio sélectionné.

voir exemple:

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

J'espère que ça le fait pour vous.

35
Inon Stelman

Ceci est ma solution. C'est assez facile.

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

    ...
}
14
petrnohejl

Tu pourrais mettre un

private int selectedIndex = -1;

puis, dans le code getView, vous pouvez vérifier 

if (position == selectedIndex) {
     rbtn.setSelected ( true );
}
else {
     rbtn.setSelected ( false );
}

et ajoutez une méthode à votre adaptateur personnalisé:

public void setSelectedIndex(int index) {
    //some range-checks, maybe
    selectedIndex = index;
    //invalidate
}

Ensuite, dans votre onItemClickedListener, vous appelez setSelectedIndex sur la position.

2
AmITheRWord

Vous devez utiliser CheckedTextView au lieu de la normale . http://developer.Android.com/reference/Android/widget/CheckedTextView.html

Je ne l'ai jamais utilisé, mais AlertDialog l'utilise pour les éléments SingleChoice. Donc ça va définitivement marcher :)

Edit: N'oubliez pas d'appeler

 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
1
Dominic Bartl

pour ajouter aux réponses déjà données, pour une approche plus modulaire, faites en sorte que tous les éléments de la liste héritent de la même classe/interface et disposent d'une fonction de message vous permettant de leur transmettre des messages via l'adaptateur.
L'adaptateur s'enregistre avec chaque élément ajouté, de sorte que chaque élément de la liste peut appeler l'adaptateur pour envoyer un message . Dans l'écouteur RadioButton, vous pouvez également envoyer un message à tous les autres boutons radio. éteignez, allumez le bouton enfoncé, puis finalement notifiez le jeu de données modifié sur l'adaptateur. 

J'ai une classe ListAdapter et une classe abstraite ListItem assez robustes; Je vais envoyer à quiconque en a besoin.
Plusieurs types d’éléments de liste pris en charge.

0
Max Izrin