2012-04-24 11 views
0

У меня возникли небольшие проблемы с моим списком. У каждого элемента есть информация и флажок. Это хорошо видно, я могу выбирать и снижать флажки и т. Д.Адаптер ListView со многими флажками

Однако я обнаружил странное поведение. Допустим, я нажал первый флажок в первой строке. Если ListView невелик, поэтому вам не нужно прокручивать вниз, это отлично работает. Но если ListView большой, поэтому мне нужно прокрутить вниз, чтобы увидеть все элементы, и некоторые случайные элементы внизу также будут нажаты. Одинаковое поведение наоборот, если я нажму на флажок в нижней части списка и прокручиваю вверх, некоторые случайные флажки также будут нажаты вверху. Если я нажму несколько флажков где-нибудь, в другом месте есть такое же количество щелчков. Я понял, что это происходит, когда вызывается GetView (...), то есть когда он обновляется. Затем он делает несколько новых флажков, но я не знаю почему.

Цените некоторую помощь здесь! :)

SSSCE моего адаптера:

public class ListViewAdapterSSCCE : BaseAdapter 
{ 
    private Activity myActivity; 
    private string[] someData; 
    private int numberOfElements; 
    private CheckBox[] boxes; 

    public ListViewAdapterSSCCE(Activity activity) 
    { 
     this.myActivity = activity; 

     for (int i = 0; i < numberOfElements; i++) 
      this.boxes[i] = new CheckBox(myActivity); 
    } 

    public void SetData(string[] someData) 
    { 
     this.someData = someData; 
     this.numberOfElements = someData.Length; 
    } 

    public void CheckAllBoxes(bool isChecked) 
    { 
     for (int i = 0; i < numberOfElements; i++) 
      this.boxes[i].Checked = isChecked; 
    } 

    public override Java.Lang.Object GetItem(int position) 
    { 
     return null; 
    } 

    public override long GetItemId(int position) 
    { 
     return 10; 
    } 

    public override int Count 
    { 
     get { return numberOfElements; } 
    } 

    public override View GetView(int position, View convertView, ViewGroup parent) 
    { 
     if (convertView == null) 
     { 
      LayoutInflater inflater = (LayoutInflater)myActivity.GetSystemService(Context.LayoutInflaterService); 
      convertView = inflater.Inflate(Resource.Layout.ChildrenList_item, null); 
     } 

     var itemBox = convertView.FindViewById<CheckBox>(Resource.Id.checkbox); 
     this.boxes[position] = itemBox; 

     var textView = convertView.FindViewById<TextView>(Resource.Id.item_data); 
     textView.Text = this.someData[position]; 

     return convertView; 
    } 
} 

ответ

2

Вы можете увидеть пример код здесь, чтобы иметь альтернативное исправление для состояния CheckBox:

custom checkbox difficulty in android

Если этот пост поможет вам, пожалуйста, отметьте это сообщение как ответ.

Спасибо.

1

Проблема, вероятно, связано с тем, как вы обрабатывать переработанные виды в адаптере. Взгляните на свой getView и проверьте, правильно ли установлен CheckBox каждого возвращаемого вами элемента в соответствии с его «моделью».

Редактировать: Я подтверждаю. Вы должны установить состояние флажка так же, как и текст вашего текста. BTW Я думаю, что обработка флажков так, как вы делаете, это плохая идея. Лучшее, что вы можете сделать, это определить «модель» для флажков (iE: простой логический [] может сделать трюк), избегая создания слишком много CheckBoxes. В вашем getView вы можете проверить соответствующее логическое значение и установить соответствующий флажок.

Для того, чтобы проверить/снимите их все, вы можете изменить булев массив в ваших checkAllBoxes затем вызовите notifyDatasetChanged(), вызывая обновление на ListView, но работает только на пунктах фактически показанных :)

+0

Вторым я видел ваш ответ, я понял проблему! Понял, что это будет что-то вроде этого. Спасибо за объяснение, а также отличное решение! –

3

Как уже говорилось, проблема в том, что вы не устанавливаете значение флажка в getView.

Также вы можете немного повысить эффективность своего кода. Первое, что вам нужно сделать, это добавить флажок к вашему представлению child xml вместо создания массива из них. Вместо этого создайте булевский массив для хранения значения.

Обратите внимание, что я изменяю это, как и для Java, поэтому могут быть некоторые вещи, которые вам нужно изменить на C#.

public class ListViewAdapterSSCCE : BaseAdapter 
    { 
    private string[] someData; 
    private int numberOfElements; 
    private boolean[] checkValue; 
    private LayoutInflater inflater; 

    public ListViewAdapterSSCCE(Context context) 
    { 

     inflater = LayoutInflater.from(context); 
    } 

    public void SetData(string[] someData) 
    { 
     this.someData = someData; 
     this.numberOfElements = someData.Length; 
    } 

    public void CheckAllBoxes(bool isChecked) 
    { 
     for (int i = 0; i < numberOfElements; i++) 
      checkValue[i] = true; 
    } 

    public override Java.Lang.Object GetItem(int position) 
    { 
     return null; 
    } 

    public override long GetItemId(int position) 
    { 
     return 10; 
    } 

    public override int Count 
    { 
     get { return numberOfElements; } 
    } 

    public override View GetView(final int position, View convertView, ViewGroup parent) 
    { 

     final ViewHolder holder; 

     if (convertView == null) 
     {    
      convertView = inflater.Inflate(Resource.Layout.ChildrenList_item, null); 

      holder = new ViewHolder(); 
      holder.itemBox = convertView.FindViewById<CheckBox>(Resource.Id.checkbox); 
      holder.textView = convertView.FindViewById<TextView>(Resource.Id.item_data); 

      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     itemBox = checkValue[position];  

     itemBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){ 

      @Override 
      public void onCheckedChanged(CompoundButton buttonView, 
        boolean isChecked) { 

         checkValue[positon] = isChecked; 

      } 

     }); 

     textView.Text = this.someData[position]; 

     return convertView; 
    } 

    class ViewHolder 
    { 
     CheckBox itemBox; 
     TextView textView; 
    } 
} 
+0

Выглядит отлично! Думал о чем-то подобном себе, увидев пост арчанос перед его редактированием, но вы положили его на бумагу, спасибо большое! –

+0

Фактически после некоторых испытаний этот подход не является законным. Проблема в том, что onCheckedChanged вызывается, когда флажок получает прокрутку с глаз долой. Поэтому это состояние не будет сохранено. Вместо этого я решил использовать OnClick, как показано ссылкой в ​​ответе Джо. –

1

mr_archano правильно, это происходит, потому что вы используете convertView, которая позволяет повторно использовать/вид рецикл в том, что больше не в поле зрения.Вот что вам нужно нужно сделать, это правильно:

Объекта для хранения состояния каждого чекбокса

Поскольку перерабатывается ваша деталь ListView, вы не можете полагаться на них, чтобы удерживать правильное положение ваш флажок. Итак, вам понадобится какой-то объект/массив, чтобы удержать правильное состояние флажка для каждого элемента списка.

Чтение из объекта

управления государственной Затем, когда вы звоните GetView, вы должны установить значение флажка на проверить/бесконтрольно, основываясь на состоянии этого объекта/массива.

Запись состояние объекта управления

Вы должны реализовать какие-то OnChecked слушателя для каждого флажка, чтобы правильно установить значение этого флажка в вашем объекте управления оператором/массиве.

Вы должны попытаться использовать ViewHolder в

ViewHolder довольно просто. Когда вы впервые создаете свой View (не используя преобразование), вы должны вызвать «FindViewByID», чтобы получить ссылки на текстовое поле и флажок. Если вы сохраните их в ViewHolder, вы сможете напрямую ссылаться на них, когда используете объект ConvertView, который будет сохранять дополнительные вызовы на «FindViewByID». Гораздо легче увидеть, как это практикуется.

Это руководство делает очень многое, что вам нужно: http://windrealm.org/tutorials/android/listview-with-checkboxes-without-listactivity.php

+0

Спасибо за дальнейшее и более подробное объяснение! Дать archano ответ, хотя с тех пор, как он был первым –

0

У меня такая же проблема, дело с большим списком. Для тех, кто любит меня, здесь, через Google, я хотел бы дать свое решение, я думаю, что это проще понять. Как отметили ребята, ListView повторно использованные виды. Поэтому вы не должны позволять виду сохранять данные.

Я использую SimpleAdapter, с настройкой настраиваемого ViewBinder, я нашел, что это легко исправить.

listItemAdapter.setViewBinder(new SimpleAdapter.ViewBinder() { 

    public boolean setViewValue(View view, Object obj, String s) { 

    if(view instanceof CheckBox){ 
     ((CheckBox)view).setChecked((Boolean)obj); 
     return true; 
    } 
    return false; 
} 
}); 

Вы должны держать свой проверили/бесконтрольно состояние по-своему.