Android

Gérer des événements dans une listeview (màj).

Bonjour à tous!

J’ai appris une nouvelle façon, plus facile, plus propre surtout, et plus « avantageuse » de gérer plusieurs événements sur une ligne dans une liste.

Souvenez-vous, j’avais réalisé et utilisé une classe qui nous gérait nos actions, aujourd’hui, nous utiliserons que le système Androïd et ses propres outils !

public class TutoAdapterActivity extends Activity {

    private ListView listview;
    private ArrayList<BeanRow> grpBr;
    private OnClickListener onClick;
    private MySecondeAdapter adapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        grpBr = new ArrayList<BeanRow>();
        BeanRow br1 = new BeanRow("Laurent", "Fritte7", false, 0);
        BeanRow br2 = new BeanRow("Benjamin", "Throrin's", false, 1);
        grpBr.add(br1);
        grpBr.add(br2);

        listview = (ListView) findViewById(R.id.listView);
        //MyAdapter adapter = new MyAdapter(getApplicationContext(), R.layout.row_tourne, grpBr);
        onClick = onClick();
        adapter = new MySecondeAdapter(getApplicationContext(), R.layout.row_tourne, grpBr, onClick);
        listview.setAdapter(adapter);
    }
}

Je n’ai rien modifié dans mon objet (liste) et mes actions seront toujours les mêmes ! Ainsi que ma vue, ce n’est que l’adapter qui changera. Tout d’abord, le constructeur change un peu, nous lui donnons un listener, que nous verrons plus tard. Allons de suite dans le nouvel adapter.

public class MySecondeAdapter extends BaseAdapter {

    private ArrayList<BeanRow> liste;
    private OnClickListener click;
    private LayoutInflater inflater;
    private int idView;
    private Holder holder;
    private Context ct;

    public MySecondeAdapter(Context applicationContext, int rowTourne,
            ArrayList<BeanRow> grpBr, OnClickListener onClick) {
        ct = applicationContext;
        liste = grpBr;
        click = onClick;
        inflater = LayoutInflater.from(applicationContext);
        idView = rowTourne;
    }

    /**
     * Ici on recupere la vue ou on la cree
     */
    public View getView(int position, View view, ViewGroup parent) {
        if (view == null) {
            holder = new Holder();
            view = inflater.inflate(idView, null);
            holder.rowIcon = (ImageView) view.findViewById(R.id.iconRow);
            holder.rowPrenom = (TextView) view.findViewById(R.id.prenomTextView);
            holder.rowPseudo = (TextView) view.findViewById(R.id.pseudoTextView);
            holder.rowAction = (ImageButton) view.findViewById(R.id.imageAction);
            holder.rowCheck = (CheckBox) view.findViewById(R.id.checkBoxRow);

            /** la vue etant cree, nous rajoutons le listener */
            holder.rowAction.setOnClickListener(click);
            holder.rowCheck.setOnClickListener(click);
            holder.rowPrenom.setOnClickListener(click);
            view.setTag(holder);
        } else {
            holder = (Holder) view.getTag();
        }
        /** je donne la position a holder, plus facile a recuperer dans le listener */
        holder.position = position;
        holder.rowPrenom.setText(liste.get(position).getPrenom());
        holder.rowPseudo.setText(liste.get(position).getPseudo());
        holder.rowCheck.setChecked(liste.get(position).isCheck());
        holder.rowIcon.setImageDrawable(switchIcon(liste.get(position).getPos()));

        boolean check = holder.rowCheck.isChecked();
        /** on redessine l'animation si coché = grisé ! */
        if (check) {
            AlphaAnimation anim = new AlphaAnimation(1, 0.2f);
            anim.setDuration(0);
            anim.setFillAfter(true);
            view.startAnimation(anim);
        } else {
            AlphaAnimation anim = new AlphaAnimation(0.2f, 1);
            anim.setDuration(0);
            anim.setFillAfter(true);
            view.startAnimation(anim);
        }

        return view;
    }

    private Drawable switchIcon(int pos) {
        Drawable icon = null;
        switch (pos) {
        case 0:
            icon = ct.getResources().getDrawable(R.drawable.labo_48x48);
            break;
        case 1:
            icon = ct.getResources().getDrawable(R.drawable.user_48x48);
            break;
        }
        return icon;
    }

    public int getCount() {
        return liste.size();
    }

    public BeanRow getItem(int position) {
        return liste.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

} 

J’ai commenté le code, pour plus de compréhension, mais nous voyons, qu’il créé une vue sur base d’une classe qui est un « mapping de l’xml » tout simplement, et nous lui donnons comme tag, l’objet en lui-même, sans oublier la position quand on récupère la vue (cela facilite la récupération dans la liste).

Nous définissons les champs qui ont besoin du listener et nous définissons une règle simple sur le checkbox, s’il est coché, on le grise, sinon on fait rien. C’est tout pour l’adapter, les événements sont gérés dans l’activity (ou une classe encore a part si on veut avoir un modèle MVC).

Voici les actions, nous constatons que je fais un switch, sur les id (de l’xml) des vues.

/**
 * Un simle listener qui gère tous les evenements de votre vue.
 * @return
 */
private OnClickListener onClick() {
    OnClickListener event = new OnClickListener() {
        public void onClick(View v) {
            View parent;
            Holder holder;

            switch (v.getId()) {

                /** Ici nous devons remonter dans la hiérarchie de la vue (dans l'xml) */
                case R.id.imageAction:
                    /** v = imagebouton */
                    parent = (View) v.getParent();
                    /** parent = le linearlayout */
                    parent = (View) parent.getParent();
                    /** parent = la vue xml qui a le Holder en tag */
                    holder = (Holder) parent.getTag();
                    Toast.makeText(getApplicationContext(), "Le pseudo de la ligne: " + grpBr.get(holder.position).getPseudo(), Toast.LENGTH_SHORT).show();
                    break;

                case R.id.checkBoxRow:
                    /** v = le checkbox */
                    parent = (View) v.getParent();
                    /** parent = la vue xml qui a le Holder en tag */
                    holder = (Holder) parent.getTag();
                    CheckBox check = (CheckBox) v;
                    if (check.isChecked()) {
                        grpBr.get(holder.position).setCheck(true);
                    } else {
                        grpBr.get(holder.position).setCheck(false);
                    }
                    /** on notifie le changement de la liste pour que le check se met à jour */
                    adapter.notifyDataSetChanged();
                    break;

                case R.id.prenomTextView:
                    /** v = textview */
                    parent = (View) v.getParent();
                    /** parent = linearlayout */
                    parent = (View) parent.getParent();
                    /** parent(écrasé) = la vue xml qui a le tag Holder */
                    holder = (Holder) parent.getTag();
                    Toast.makeText(getApplicationContext(), "Le prenom de la ligne: " + grpBr.get(holder.position).getPrenom(), Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
    return event;
}

Étant donné que lorsqu’on fait view.getId(), nous récupérons l’id de la vue ainsi, nous pouvons tester la valeur et définir nos événements. Ensuite, il faut suivre la hiérarchie de votre vue xml, c’est pourquoi je fais des view.getParent(), c’est pour monter dans la hiérarchie.

Je peux ainsi, remonter à la base, et récupérer mon tag, qui n’est autre que l’objet Holder de l’adapter. On récupère les données et la position sans problème, et nous lançons les événements.

Voilà, j’espère avoir été plus clair que la dernière fois, et que vous préfériez cette méthode-ci. Je vous ai ré-uploadé sur code.google le projet complet, avec les deux adapters.