39 votes

ListView: setItemChecked fonctionne uniquement avec ArrayAdapter standard - ne fonctionne PAS lorsque l'on utilise un ArrayAdapter personnalisé.

C'est vraiment bizarre.

Lorsque j'utilise le ArrayAdapter standard pour un ListView, l'appel à setItemChecked fonctionne bien

Mais lorsque j'utilise un ArrayAdapter personnalisé, cela ne fonctionne pas.

Quelle pourrait en être la raison? Est-ce un bug? Ou est-ce que je passe à côté de quelque chose?

public class Test_Activity extends Activity {

    /** Appelée lorsque l'activité est créée pour la première fois. */
    private List list;
    private ListView lView;

    public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    // Crée un tableau de chaînes de caractères, qui sera mis dans notre ListActivity
    setContentView(R.layout.main);
    lView = (ListView) findViewById(R.id.ListView01);
    lView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

    list = getModel();

    //avec cet adaptateur setItemChecked fonctionne correctement
    lView.setAdapter(new ArrayAdapter(this,
        android.R.layout.simple_list_item_multiple_choice, list));

  //**************************
    //PROBLÈME : avec cet adaptateur, aucun élément n'est vérifié sur l'écran
    // ArrayAdapter adapter = new Test_Class1(this, list);
    // lView.setAdapter(adapter);

    }

    private List getModel() {
       List list = new ArrayList();
       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"));
       // Sélectionnez initialement l'un des éléments
       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); // sélectionne l'élément uniquement pour l'ArrayAdapter standard

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

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

public class Test_Class1 extends ArrayAdapter {

    private final List list;
    private final Activity context;

 public Test_Class1(Activity context, List 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;
    }

}

47voto

CommonsWare Points 402670

Votre mise en page de ligne doit être Checkable pour que setItemChecked() fonctionne, auquel cas Android se chargera d'appeler setChecked() sur votre Checkable lorsque l'utilisateur clique sur la ligne. Vous n'auriez pas besoin de configurer votre propre OnCheckedChangeListener.

Pour en savoir plus, consultez :

12voto

moondroid Points 398

Vous devez définir le mode de choix pour votre ListView, par exemple :

list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

Mais si vous utilisez également une disposition personnalisée pour votre élément de liste (R.layout.drawing_list_item), alors vous devez vous assurer que votre disposition implémente l'interface Checkable :

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

Ensuite, votre disposition vérifiable sera définie comme l'exemple suivant :

1voto

stephen Points 517

Checkable est une courbe d'apprentissage que je préfère ne pas prendre pour le moment. Vous pouvez définir et définir manuellement la case à cocher (CheckBox) dans l'OnItemClickListener des activités. Maintenez une variable transitoire booléenne isChecked dans la liste des MyObject dans l'ArrayAdapter.

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 cliquant sur la case à cocher (CheckBox) elle-même; utilisez la même logique d'ajout (addItem)/suppression (removeItem) dans l'implémentation getView de votre adaptateur de tableau personnalisé, dans l'OnClickListener de la CheckBox.

public View getView(int position, View convertView, ViewGroup viewGroup) {
        CheckBox cb = null;
        if (convertView == null) {
            if(inflater == null) //cache pour éviter la reconstruction pour chaque vue
            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()) //vérifiez la logique booléenne ici !!!
                        activityRef.get().addItem(cb.getTag()); //Référence faible vers l'activité
                    else
                        activityRef.get().removeItem(cb.getTag());

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

Appeler CheckBox::setChecked() est la clé ici.
Cela semble fonctionner tant que votre adaptateur de tableau peut supposer la même activité, et que votre adaptateur de tableau peut supposer la même définition d'élément de liste XML dans res/layout/.

élément de liste à cocher XML :

Si vous avez besoin de cocher certaines de vos cases à cocher (CheckBox) initialement, définissez simplement vos membres isChecked dans votre MyObject avant l'inflation.

0voto

Alex Points 779

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

_expandableListView.Post(() =>
{
    _expandableListView.SetItemChecked(fragmentPosition, true);
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X