Android ListView с RadioButton в режиме singleChoice и пользовательским расположением строк - PullRequest
26 голосов
/ 23 ноября 2010

У меня есть ListView , который находится в режиме singleChoice . Все, что я хочу, это отобразить кнопку RadioButton в сторону, чтобы при нажатии была выделена подсветка, чтобы сказать, что она выбрана, а когда нажата другая кнопка, она возвращается к невыбранной, а новая становится выбранной. Почему это так сложно? Это не должно быть так сложно. Я потратил ДНЕЙ в поисках подходящего ответа на этот вопрос, и я ничего не нашел, поэтому я прошу, надеюсь, в ясной и сжатой форме.

Мой макет для просмотра списка (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>

Моя пользовательская строка (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>

Мой onCreate () Метод:

@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");
}

Теперь все, что лежит в основе, работает как положено, вы нажимаете на кнопку радио, и через ее тег я могу соответствующим образом выбрать этот элемент из списка и манипулировать им так, как я хочу. Однако при нажатии первой кнопки-переключателя будет выбрана последняя. Нажмите эту же кнопку еще раз, и теперь она также выбрана. Нажмите на нее еще раз, и ничего не происходит, будут выбраны как последний, так и первый. Теперь я нажимаю любой другой в списке, он выбирается, как ожидалось. Нажмите любую из выбранных радиокнопок, и ничего не происходит, радиокнопка остается выбранной.

Я попытался использовать следующее в 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");
}

и это просто показывает отсутствие переключателей вообще. УДИВИТЕЛЬНЫЙ .

Теперь, может быть (читай: скорее всего), я просто дремучий и не могу понять это, но я видел, что этот вопрос часто задавали без реального ответа. Много ссылок на другие учебники или на книгу парня из Commonsware. Тем не менее, комментарии уже устарели, и его хранилище изменилось настолько, что это уже не правильные ответы.

Итак, у кого-нибудь есть идеи, как извлечь из этого ожидаемую функциональность? Или, если это не удалось, просто передайте мне исходный код приложения GMail. :)

Ответы [ 7 ]

8 голосов
/ 23 ноября 2010

Имейте в виду, что в строке ListView элементы RECYCLED. Это может объяснить, почему действия в одном ряду влияют на другой. Покопайтесь в книге Марка, и вы найдете освещение этого.

Если вы используете адаптер со списком, вы можете использовать getView () на адаптере, чтобы добавить обработчик щелчков к каждой строке при ее создании / переработке и убедиться, что состояние управляется правильно, так как элементы строки создано и переработано.

Мой подход состоит в том, чтобы сохранить состояние в моей собственной структуре данных, а затем использовать getView (), чтобы отразить это в пользовательском интерфейсе, когда пользователь прокручивает вверх и вниз ListView. Возможно, есть лучшее решение, но оно мне подходит.

7 голосов
/ 10 августа 2012

Простое решение:

Добавьте эту строку в макет RadioButton вашего xml-файла:

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

Затем в классе действий, который использует ListView, добавьте следующее:

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

С этим простым кодом проверяется только одна кнопка RadioButton.Если вы дотронетесь до того, который уже отмечен, то он вернется в непроверенный режим.

«listIndex» отслеживает отмеченный элемент, -1 если нет.

Если вы хотите сохранить всегдаодин проверенный, тогда код в onClickRadioButton должен быть:

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

        if (listRadioButton != null) {
                listRadioButton.setChecked(false);
        }
        listRadioButton = (RadioButton) v;
        listIndex = newIndex; 
    }
3 голосов
/ 09 мая 2012

Меня зовут Гураб Сингха.Я решил этот вопрос.Я написал этот кодекс, чтобы решить его.Я надеюсь, что это поможет вам всем.Благодарю.Мне нужно 3 часа для этого.

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();


    }

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>
2 голосов
/ 09 августа 2011

У меня только что была похожая проблема. Казалось, что это связано с переработкой просмотров. Но я добавил Лог везде и заметил, что обработка отходов была в порядке. Проблема была в обработке RadioButtons. Я использовал:

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

и правильный способ сделать это:

if(answer == DBAdapter.YES){
   rbYes.setChecked(true); 
}
else if(answer == DBAdapter.NO){
   rbNo.setChecked(true);
}
else{
   RadioGroup rg = (RadioGroup)(holder.answerView);
   rg.clearCheck();
}                
1 голос
/ 26 октября 2015

Вы можете достичь гораздо более простого, следуйте этому. Это было опробовано в MarshMallow

1) Иметь 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 будет отображаться RadioButton.

  • ListChoiceIndicatorMultiple будет отображаться CheckBox

Не забудьте поставить choiceMode:Single в свой ListView.

0 голосов
/ 14 декабря 2015

внутри адаптера

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

добавить стиль к переключателю

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

и в xml используйте стиль переключателя

<?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>
0 голосов
/ 07 апреля 2015

На вашем адаптере:

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

На вашей деятельности / фрагмент:

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

        }
    });
...