2010-11-22 7 views
25

J'ai un ListView, qui est en singleChoice mode. Tout ce que je veux, c'est afficher un RadioButton sur le côté, que lorsque l'on clique sur les faits saillants pour dire qu'il est sélectionné, et que l'on clique sur un bouton différent, on retourne à non sélectionné et le nouveau devient sélectionné. Pourquoi est-ce si difficile? Cela ne devrait pas être si compliqué. J'ai passé jours à la recherche d'une réponse appropriée à cela et je n'ai rien trouvé, donc je demande avec optimisme d'une manière claire et concise.Android ListView avec RadioButton en mode singleChoice et une disposition de ligne personnalisée

Ma mise en page pour la listview (R.layout.view_orders):

<?xml version="1.0" encoding="utf-8"?> 
<ListView 
     android:choiceMode="singleChoice" 
     android:id="@android:id/list" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:divider="@drawable/list_divider" 
     android:dividerHeight="1px" 
     android:focusable="false" 
     android:focusableInTouchMode="false" 
     android:cacheColorHint="#00000000"> 
</ListView> 

Ma coutume ligne (R.layout.orders_row):

<?xml version="1.0" encoding="utf-8"?> 

<RelativeLayout 
    xmlns:app="http://schemas.android.com/apk/res/com.xxx.xxxxxx" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal" 
    android:padding="6dip"> 

    <com.xxx.xxxxxx.VerticalLabelView 
     app:text="SHORT" 
     app:textColor="#666" 
     app:textSize="14sp" 
     android:id="@+id/state" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_centerVertical="true" /> 

    <TextView 
     android:id="@+id/quantity" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_toRightOf="@id/state" 
     android:layout_centerVertical="true" 
     android:gravity="center" 
     android:textSize="40sp" 
     android:layout_margin="2dip" 
     android:minWidth="30dip" 
     android:textColor="#555" /> 


    <RelativeLayout 
     android:layout_toRightOf="@id/quantity" 
     android:layout_centerVertical="true" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content"> 

     <TextView 
      android:id="@+id/instrument" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:textSize="20sp" 
      android:textColor="#333" 
      android:layout_marginLeft="2dip" 
      android:layout_marginRight="2dip" 
      /> 


     <TextView 
      android:id="@+id/deets" 
      android:layout_below="@id/instrument" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:textSize="16sp" 
      android:textColor="#888" 
      android:layout_marginLeft="2dip" 
      android:layout_marginRight="2dip" 
      /> 

    </RelativeLayout> 

     <RadioButton 
      android:id="@+id/selector" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentRight="true" 
      android:layout_centerVertical="true" 
      /> 

</RelativeLayout> 

Mon onCreate () méthode:

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.view_orders); 
    client = new Client(handler); 
    ola = new OrdersAdapter(this, R.layout.orders_row, Orders); 
    setListAdapter(ola); 
    final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); 
    panel = (PositionsPanel) findViewById(R.id.panel); 
    Utility.showProgressBar(loading); 
    client.Connect("orders"); 
} 

Maintenant que tout sous-jacent fonctionne comme prévu, vous cliquez sur un radiobutton et grâce à son tag, je peux sélectionner cet élément de la liste et le manipuler comme je le souhaite. Cependant, lorsque le premier bouton radio est cliqué, le dernier sera sélectionné. Cliquez à nouveau sur ce même bouton radio et il est maintenant sélectionné. Cliquez encore une fois et rien ne se passe, le dernier et le premier sont sélectionnés. Maintenant, je clique sur un autre sur la liste, il est sélectionné comme prévu. Cliquez sur l'un des boutons radio sélectionnés et rien ne se passe, le bouton radio reste sélectionné.

J'ai essayé d'utiliser ce qui suit dans onCreate():

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.view_orders); 
    client = new Client(handler); 
    ola = new OrdersAdapter(this, android.R.layout.simple_list_item_single_choice, Orders); 
    setListAdapter(ola); 
    final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); 
    panel = (PositionsPanel) findViewById(R.id.panel); 
    Utility.showProgressBar(loading); 
    client.Connect("orders"); 
} 

et qui montre tout simplement pas les boutons radio du tout. IMPRESSIONNELLE.

Maintenant peut-être (lire: très probablement), je suis juste dense et ne peux pas comprendre cela, mais j'ai vu cette question posée beaucoup avec aucune vraie réponse. Beaucoup de références à d'autres tutoriels ou au livre du gars Commonsware. Cependant, les commentaires sont vieux maintenant et son référentiel a tellement changé, que ce ne sont plus des réponses correctes.

Alors, est-ce que quelqu'un a une idée de la façon d'obtenir les fonctionnalités attendues? Ou à défaut, il suffit de me passer le code source de l'application GMail. :)

Répondre

8

Gardez à l'esprit que les éléments de la ligne ListView sont RECYCLED. Ceci est susceptible d'expliquer pourquoi les actions sur une ligne en affectent une autre. Creusez dans le livre de Mark et vous trouverez une couverture de cela. Si vous utilisez un adaptateur avec la liste, vous pouvez utiliser getView() sur un adaptateur pour ajouter un gestionnaire de clic à chaque ligne lors de sa création/recyclage et vérifier que l'état est correctement géré en tant qu'éléments de ligne sont créés et recyclés.

Mon approche consiste à stocker l'état dans ma propre structure de données, puis d'utiliser getView() pour le refléter dans l'interface utilisateur lorsque l'utilisateur fait défiler la liste vers le haut et vers le bas. Il y a peut-être une meilleure solution, mais cela fonctionne pour moi.

+0

Donc c'est exactement ce qui se passe. Je ne sais pas pourquoi aucune des autres réponses n'a pas simplement énoncé ce simple fait. Après avoir réalisé que j'utilisais un convertView et que je le recyclais, c'était vraiment évident. Une minute ou deux de googling et je sais comment résoudre ceci. J'ai regardé dans le livre de Mark, Chapitre 9, "Getting Fancy With Lists" et son exemple de RateList est détaillé ici, ce qui l'explique assez clairement. Toute personne ayant ce problème vérifier ce chapitre de Beginning Android par Mark Murphy. –

+0

Ces types de bizarreries dans Android en font une courbe d'apprentissage abrupte, mais une fois compris, nous obtenons les avantages de performance du recyclage. –

+0

Alors ça n'a pas fonctionné, je l'ai parcouru et, bien que le recyclage soit la raison de ce que je vois, le livre de Mark ne détaille pas comment résoudre le problème que je rencontre. –

2

Je viens d'avoir un problème similaire. Il semblait que c'était lié au recyclage des vues. Mais j'ai ajouté Log partout et j'ai remarqué que la manipulation de recyclage était bien. Le problème était la gestion de RadioButtons. j'utilisais:

if(answer == DBAdapter.YES){ 
    rbYes.setChecked(true); 
    rbNo.setChecked(false);      
} 
else if(answer == DBAdapter.NO){ 
    rbYes.setChecked(false); 
    rbNo.setChecked(true); 
} 
else{ 
    rbYes.setChecked(false); 
    rbNo.setChecked(false); 
}     

et la bonne façon de le faire est:

if(answer == DBAdapter.YES){ 
    rbYes.setChecked(true); 
} 
else if(answer == DBAdapter.NO){ 
    rbNo.setChecked(true); 
} 
else{ 
    RadioGroup rg = (RadioGroup)(holder.answerView); 
    rg.clearCheck(); 
}     
3

My Name Is Gourab Singha. J'ai résolu ce problème. J'ai écrit ce code pour le résoudre. J'espère que cela vous aide tous. Merci. J'ai besoin de 3 heures pour cela.

public void add_option_to_list(View v){ 


    LinearLayout ll = (LinearLayout)v.getParent(); 
    LinearLayout ll_helper = null; 
    LinearLayout ll2 = (LinearLayout)ll.getParent(); 
    LinearLayout ll3 = (LinearLayout)ll2.getParent(); 

    ListView ll4 = (ListView)ll3.getParent(); 
    //RadioButton rb1= (RadioButton)ll.getChildAt(1); 
    Toast.makeText(getApplicationContext(), ", "+ll4.getChildCount(), Toast.LENGTH_LONG).show();  
    //ll.findViewById(R.id.radio_option_button) 
    for(int k=0;k<ll4.getChildCount();k++){ 

     ll3 = (LinearLayout)ll4.getChildAt(k); 
     ll2 = (LinearLayout)ll3.getChildAt(0); 
     ll_helper = (LinearLayout)ll2.getChildAt(0); 
     RadioButton rb1 = (RadioButton)ll_helper.getChildAt(1); 
     if(rb1.isChecked()) 
     rb1.setChecked(false); 


    } 
    RadioButton rb1 = (RadioButton)ll.getChildAt(1); 
    rb1.setChecked(true); 
    //Toast.makeText(getApplicationContext(), ""+((TextView)ll.getChildAt(4)).getText().toString(), Toast.LENGTH_LONG).show(); 


    } 

Le XML:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <LinearLayout 

     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" > 


     <LinearLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="horizontal" > 

      <TextView 
       android:id="@+id/id" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Category Name" 
       android:textAppearance="?android:attr/textAppearanceMedium" 
       android:visibility="gone" /> 

      <RadioButton 
       android:id="@+id/radio_option_button" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:onClick="add_option_to_list" 
       android:text="" /> 

      <TextView 
       android:id="@+id/option_name" 
       android:layout_width="wrap_content" 
       android:layout_height="fill_parent" 
       android:layout_marginLeft="3dp" 
       android:layout_weight="5.35" 
       android:text="Category Name" 
       android:textAppearance="?android:attr/textAppearanceMedium" /> 



      <TextView 
       android:id="@+id/option_price" 
       android:layout_width="76dp" 
       android:layout_height="wrap_content" 
       android:layout_marginRight="10dp" 
       android:gravity="right" 
       android:text="$0.00" 
       android:textAppearance="?android:attr/textAppearanceMedium" /> 

      <TextView 
       android:id="@+id/option_unit_price" 
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginRight="5dp" 
       android:gravity="right" 
       android:text="$0.00" 
       android:textAppearance="?android:attr/textAppearanceMedium" 
       android:visibility="gone" /> 
     </LinearLayout> 

    </LinearLayout> 

</LinearLayout> 
+17

Bienvenue dans Stack Overflow. J'ai édité votre réponse pour la rendre facile à lire. En passant, vous n'avez pas besoin d'écrire votre nom dans votre réponse; Votre nom est toujours affiché à la fin de votre réponse. –

7

J'ai testé une solution plus simple:

Ajoutez cette ligne dans le RadioButton de votre fichier xml:

<RadioButton 
    ... 
    android:onClick="onClickRadioButton" 
    ... 
/> 

Puis dans l'activité classe qui utilise ListView, ajoutez ce qui suit:

private RadioButton listRadioButton = null; 
    int listIndex = -1; 

    public void onClickRadioButton(View v) { 
     View vMain = ((View) v.getParent()); 
     // getParent() must be added 'n' times, 
     // where 'n' is the number of RadioButtons' nested parents 
     // in your case is one. 

     // uncheck previous checked button. 
     if (listRadioButton != null) listRadioButton.setChecked(false); 
     // assign to the variable the new one 
     listRadioButton = (RadioButton) v; 
     // find if the new one is checked or not, and set "listIndex" 
     if (listRadioButton.isChecked) { 
      listIndex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain); 
     } else { 
      listRadioButton = null; 
      listIndex = -1 
     } 
    } 

Avec ce code simple, un seul RadioButton est vérifié. Si vous touchez celui qui est déjà coché, il revient au mode non coché. "ListIndex" effectue le suivi de l'élément coché, -1 s'il n'en existe aucun.

Si vous voulez toujours garder un cochée, code onClickRadioButton devrait être:

public void onClickRadioButton(View v) { 
     View vMain = ((View) v.getParent()); 
     int newIntex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain); 
     if (listIndex == newIndex) return; 

     if (listRadioButton != null) { 
       listRadioButton.setChecked(false); 
     } 
     listRadioButton = (RadioButton) v; 
     listIndex = newIndex; 
    } 
+1

Salut, cela fonctionne quand la liste tient dans une page, mais quand la liste est plus longue qu'une page, listIndex est fauché car il commence à compter à partir du premier élément de liste visible plutôt que du début réel de la liste. Comment cela peut-il être défini? – user1118764

+0

thankxx fonctionne bien .. !! –

-1

Sur votre adaptateur:

public void setChecked(View v, int position) { 

    ViewGroup parent = ((ViewGroup) v.getParent()); // linear layout 

    for (int x = 0; x < parent.getChildCount() ; x++) { 

     View cv = parent.getChildAt(x); 
     ((RadioButton)cv.findViewById(R.id.checkbox)).setChecked(false); // your checkbox/radiobtt id 
    } 

    RadioButton radio = (RadioButton)v.findViewById(R.id.checkbox); 
    radio.setChecked(true); 
} 

Sur votre activité/fragment:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
     @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
      ((ModelNameAdapter)adapter).setChecked(view, position); 

     } 
    }); 
+0

La position n'est jamais utilisée dans votre méthode de vérification. –

+0

ne fonctionne pas .. !! –

+0

Pour que cela fonctionne, vous ne devez pas recycler vos vues. Ne faites pas: si convertView == null {convertir = gonfler}, gonflez toujours un nouveau. – sagits

1

Vous pouvez réaliser beaucoup plus simple, suivez ceci. Il a été jugé en Guimauve

1) Avoir un CheckedTextView:

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:checkMark="?android:attr/listChoiceIndicatorSingle" 
    android:padding="10dp" 
    android:textAppearance="?android:attr/textAppearanceMedium"> 

  • ListChoiceIndicatorSingle affiche RadioButton.

  • ListChoiceIndicatorMultiple affichera CheckBox

Ne pas oublié de mettre choiceMode:Single dans votre ListView.

0

intérieur de l'adaptateur

viewHolder.radioBtn.setOnClickListener(new OnClickListener() { 

       @Override 
       public void onClick(View v) { 
        Log.e("called", "called"); 
        if(position != mSelectedPosition && mSelectedRB != null){ 
         mSelectedRB.setChecked(false); 
        } 



        mSelectedPosition = position; 
        mSelectedRB = (RadioButton)v; 
       } 
      }); 

      viewHolder.radioBtn.setText(mList[position]); 
      if(mSelectedPosition != position){ 
       viewHolder.radioBtn.setChecked(false); 

      }else{ 
       viewHolder.radioBtn.setChecked(true); 

       if(mSelectedRB != null && viewHolder.radioBtn != mSelectedRB){ 
        mSelectedRB = viewHolder.radioBtn; 
       } 
      } 

ajouter le style du bouton radio

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 

    <item android:drawable="@drawable/tick" android:state_checked="true"/> 
    <item android:drawable="@drawable/untick" android:state_checked="false"/> 

</selector> 

et dans le fichier XML utiliser le style de bouton radio

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <RadioButton 
     android:id="@+id/radioBtn" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" 
     android:button="@null" 
     android:checked="true" 
     android:drawablePadding="30dp" 
     android:drawableRight="@drawable/checkmark" 
     android:text="first" /> 

</RelativeLayout> 
Questions connexes