ListView: setItemChecked ne fonctionne qu'avec ArrayAdapter standard - ne fonctionne pas lorsque vous utilisez ArrayAdapter personnalisé?

C'est vraiment bizarre.

quand j'utilise le tableau standard pour une ListView appelant des travaux contrôlés par setitem OK

mais lorsqu'on utilise un tableau sur mesure, ce n'est pas le cas.

Quelle en serait la raison? Est-ce un bug? Ou ai-je raté quelque chose?

public class Test_Activity extends Activity {

    /** Called when the activity is first created. */
    private List<Model> list;
    private ListView lView;

    public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    // Create an array of Strings, that will be put to our ListActivity
    setContentView(R.layout.main);
    lView = (ListView) findViewById(R.id.ListView01);
    lView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

    list = getModel();

    //with this adapter setItemChecked works OK
    lView.setAdapter(new ArrayAdapter<Model>(this,
        android.R.layout.simple_list_item_multiple_choice, list));


  //**************************
    //PROBLEM: with this adapter it does not check any items on the screen
    // ArrayAdapter<Model> adapter = new Test_Class1(this, list);
    // lView.setAdapter(adapter);



    }

    private List<Model> getModel() {
       List<Model> list = new ArrayList<Model>();
       list.add(get("0"));
       list.add(get("1"));
       list.add(get("2"));
       list.get(1).setSelected(true);
       Model m = list.get(1);
       list.add(get("3"));
       list.add(get("4"));
       list.add(get("5"));
       list.add(get("6"));
       list.add(get("7"));
       // Initially select one of the items
       return list;
    }

    private Model get(String s) {
       return new Model(s);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       MenuInflater inflater = getMenuInflater();
       inflater.inflate(R.menu.results_screen_option_menu, menu);
       return true;
    }

    /**
     * @category OptionsMenu
     */
    @Override
 public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.select_all: {

        int size = lView.getAdapter().getCount();

        for (int i = 0; i <= size; i++) {

            //************************** PROBLEM
        lView.setItemChecked(i, true); // selects the item only for standard ArrayAdapter

    Log.i("xxx", "looping " + i);
        }
    }
        return true;
    case R.id.select_none:
        return true;
    }
    return false;
    }
}

//------------------------------------------------------------

public class Test_Class1 extends ArrayAdapter<Model> {

    private final List<Model> list;
    private final Activity context;

 public Test_Class1(Activity context, List<Model> list) {
    super(context, R.layout.rowbuttonlayout2, list);
    this.context = context;
    this.list = list;
    }

  static class ViewHolder {
    protected TextView text;
    protected CheckBox checkbox;
    }

    @Override
 public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;
    Log.i("xxx", "-> getView " + position);
    if (convertView == null) {
        LayoutInflater inflator = context.getLayoutInflater();
        view = inflator.inflate(R.layout.rowbuttonlayout, null);
        final ViewHolder viewHolder = new ViewHolder();
        viewHolder.text = (TextView) view.findViewById(R.id.label);
        viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check);
        viewHolder.checkbox
            .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {
                Model element = (Model) viewHolder.checkbox
                    .getTag();
                Log.i("xxx", "-> onCheckedChanged");
                element.setSelected(buttonView.isChecked());
                Log.i("xxx", "<- onCheckedChanged");

            }
            });
        view.setTag(viewHolder);
        viewHolder.checkbox.setTag(list.get(position));
    } else {
        view = convertView;
        ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
    }
    ViewHolder holder = (ViewHolder) view.getTag();
    holder.text.setText(list.get(position).getName());
    Log.i("xxx", "holder.checkbox.setChecked: " + position);

    holder.checkbox.setChecked(list.get(position).isSelected());
    Log.i("xxx", "<-  getView " + position);

    return view;
    }

}
36
demandé sur Pi Delport 2011-12-03 21:49:54

4 réponses

votre disposition de ligne doit être Checkable pour setItemChecked() de travailler, dans ce cas, Android gérera appel setChecked() sur votre Checkable que l'utilisateur clique sur la ligne. Vous n'auriez pas besoin de mettre en place votre propre OnCheckedChangeListener .

pour plus, voir:

46
répondu CommonsWare 2017-05-23 11:46:11

pour sûr vous devez définir le mode de choix pour votre ListView, par exemple:

list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

mais si vous utilisez également un layout personnalisé pour votre élément de liste ( R.layout.drawing_list_item ), alors vous devez vous assurer que votre layout implémente l'interface vérifiable:

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
    private boolean isChecked = false;

    public CheckableRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean isChecked) {
        this.isChecked = isChecked;
        changeColor(isChecked);
    }

    public void toggle() {
        this.isChecked = !this.isChecked;
        changeColor(this.isChecked);
    }

    private void changeColor(boolean isChecked){
        if (isChecked) {
            setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
        } else {
            setBackgroundColor(getResources().getColor(android.R.color.transparent));
        }
    }
}

alors votre mise en page vérifiable sera définie comme l'exemple suivant:

<?xml version="1.0" encoding="utf-8"?>
<it.moondroid.banking.CheckableRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_item_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp" >

    <ImageView
        android:id="@+id/agenzie_item_icon"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@android:color/darker_gray"
        android:focusable="false" />

    <TextView
        android:id="@+id/agenzie_item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/agenzie_item_icon"
        android:focusable="false"
        android:paddingLeft="10dp"
        android:text="item"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#FFFFFF" />

</it.moondroid.banking.CheckableRelativeLayout>
10
répondu moondroid 2017-12-15 23:13:08

Checklable est une courbe d'apprentissage que je préfère ne pas prendre maintenant. Vous pouvez définir et désactiver la case à cocher manuellement dans les activités OnItemClickListener . Maintenir une variable transitoire booléenne isChecked dans la liste MyObject dans la liste ArrayAdapter<MyObject> .

public void onItemClick(AdapterView<?> av, View v, int position, long arg3) {
    final ListView listView = (ListView) findViewById(android.R.id.list);
    MyObject item = (MyObject) listView.getItemAtPosition(position);
    item.isChecked = !item.isChecked;
    if(item.isChecked)
        addItem(item);
    else
        removeItem(item);
}  

pour tenir compte des utilisateurs qui cliquent sur le CheckBox lui-même; utilisez la même logique addItem(item)/removeItem(item) dans l'implémentation getView de votre adaptateur de tableau personnalisé, dans l'implémentation CheckBox OnClickListener .

public View getView(int position, View convertView, ViewGroup viewGroup) {
        CheckBox cb = null;
        if (convertView == null) {
            if(inflater == null) //cache to avoid reconstructing for each view
            inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView =inflater.inflate(R.layout.list_item_text_right_checkmark, null);

            CheckBox cb = (CheckBox) convertView.findViewById(R.id.check);
            cb.setChecked((list.get(position).isChecked));
            cb.setTag(list.get(position);
            public void onClick(View v) {
                if(v instanceof CheckBox) {
                    CheckBox cb = (CheckBox) v;
                    if(cb.isChecked()) //verify boolean logic here!!!
                        activityRef.get().addItem(cb.getTag()); //WeakReference to activity
                    else
                        activityRef.get().removeItem(cb.getTag());

                }
            });
    } else cb = (CheckBox) convertView.findViewById(R.id.check);
    cb.setChecked((list.get(position).isChecked));
...
}

appelle la case à cocher:: setChecked () est la clé ici.

Cela semble faire l'affaire aussi longtemps que votre adaptateur de tableau peut assumer la même activité, et votre adaptateur de tableau peut assumer la même définition xml d'élément de liste dans res/layout/.

élément de la liste à vérifier 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"
    android:orientation="vertical" >

  <TextView
      android:id="@+id/text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_toLeftOf="@+id/check"
      android:gravity="center_vertical"
      android:paddingLeft="8dp"
      android:textAppearance="?android:attr/textAppearanceMedium" />

  <CheckBox
    android:id="@+id/check"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:focusable="false"/>
</RelativeLayout>

si vous avez besoin de vérifier certaines de vos cases à cocher initialement, il suffit de définir vos membres isChecked dans votre MyObject avant de gonfler.

1
répondu stephen 2013-09-13 19:20:57

aucune des réponses n'a fonctionné pour moi. Mon problème était que seul l'appel initial à ExpandableListView.setItemChecked de OnCreate/Démarrage/OnPause ne fonctionne pas, comme si la vue n'était pas entièrement initialisé encore. Pour résoudre ce problème, j'ai dû faire ce qui suit:

_expandableListView.Post(() =>
{
    _expandableListView.SetItemChecked(fragmentPosition, true);
});
0
répondu Alex 2017-08-03 18:23:48