Aller au contenu

SectionListAdapter


Pierre87

Recommended Posts

Comme je trouvais le BaseAdapter un peut trop simpliste, j'ai décidé d'en coder un assez sympa : SectionListAdapter :P

(c'est assez proche de ExpandableMachin, mais sans le bling bling "expandable")

Le principe :

- ça s'utilise sur une ListView ou une ListActivity directement (pas besoin d'une nouvelle classe)

- la liste est découpée en "section", et les section en "row" (lol iPhone)

- SectionListAdapter hérite de BaseAdapter

- Les méthodes de BaseAdapter sont déjà implémentées

- Il y a de nouvelles méthodes à implémenter, avec "section+row" à la place de "position"

Le point fort : on peut définir le nombre de sections, et la TAILLE d'une section.

L'intérêt de pouvoir définir une taille pour une section, c'est qu'en définissant sa taille à 0, on peut la masquer \o/

Ok, on pouvait déjà faire ça avec le BaseAdapter, mais SectionListAdapter permet de le faire plus facilement, et plus proprement

Il y a aussi un système de cache, mais il est à améliorer.

Je me demande quelles sont les données intéressantes à mettre en cache ...

public abstract class SectionListAdapter extends BaseAdapter
{
   private HashMap sectionRows;

   public SectionListAdapter()
   {
       super();

       this.sectionRows = new HashMap();
   }

   public void notifyDataSetChanged()
   {
       this.sectionRows.clear();

       super.notifyDataSetChanged(); // notify after clear
   }

   public int getCount()
   {
       int count = 0;

       int sectionCount = this.getSectionCount();

       for (int section = 0; section < sectionCount; section++)
       {
           count += this.getRowCount(section);
       }

       return count;
   }

   public Object getItem(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       Object o = this.getItem(sectionRow[0], sectionRow[1]);

       return o;
   }

   public long getItemId(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       long id = this.getItemId(sectionRow[0], sectionRow[1]);

       return id;
   }

   public View getView(int position, View convertView, ViewGroup parent)
   {
       int[] sectionRow = this.getSectionRow(position);

       convertView = this.getView(sectionRow[0], sectionRow[1], convertView, parent);

       return convertView;
   }

   public int getItemViewType(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       int itemViewType = this.getItemViewType(sectionRow[0], sectionRow[1]);

       return itemViewType;
   }

   private int[] getSectionRow(int position)
   {
       int[] sectionRow = this.sectionRows.get(position);

       if (sectionRow == null)
       {
           int p = position;
           int sectionCount = this.getSectionCount();

           for (int i = 0; i < sectionCount; i++)
           {
               int rowCount = this.getRowCount(i);

               if (p < rowCount)
               {
                   sectionRow = new int[] { i, p };

                   break;
               }

               p -= rowCount;
           }

           if (sectionRow == null)
           {
               sectionRow = new int[] { -1, -1 };
           }

           this.sectionRows.put(position, sectionRow);
       }

       return sectionRow;
   }

   public abstract int getSectionCount();

   public abstract int getRowCount(int section);

   public abstract Object getItem(int section, int row);

   public abstract long getItemId(int section, int row);

   public abstract int getItemViewType(int section, int row);

   public abstract View getView(int section, int row, View convertView, ViewGroup parent);
}

Lien vers le commentaire
Partager sur d’autres sites

Imaginons une liste ayant cette structure :

TITRE

A

a1

a2

a3

B

b1

b2

C

c1

c2

c3

c4

TITRE est une View unique, affiché en toute circonstance

A B et C sont des sous titres, au début de groupes d'éléments (ce sont des vues du même type)

a(n) b(n) et c(n) sont des éléments, ils utilisent tous le même type de vue

Les données éléments des 3 groupes A B et C sont stockées dans 3 List indépendantes (pour une meilleure structuration)

Si une List est vides, il n'y a aucun élément affiché, et le sous titre correspondant (A par exemple) n'est pas affiché

De plus, si les 3 listes sont vides, je veux afficher une ligne "no result" (en plus du TITRE)

Par conséquent :

J'ai 8 "sections" :

- TITRE

- sous titre A

- éléments a

- sous titre B

- éléments b

- sous titre C

- éléments c

- no result

J'ai 4 types de vue différentes :

- TITRE

- sous titre

- éléments

- no result

(bon ok, c'est un peu compliqué, mais c'est un extrait simplifié d'un cas sur lequel je travaille)

C'est tout à fait possible de le faire avec un simple ListAdapter

Mais à mon avis, le code va être bien crade :D

En utilisant SectionListAdapter, on peut structurer le code plus facilement \o/

Désolé de ne pas pouvoir fournir de code, mais je n'en ai pas sous la main, et je ne suis pas sûr que ce soit utile :/

Lien vers le commentaire
Partager sur d’autres sites

  • 4 weeks later...

en voilà une nouvelle version

plus complète, plus optimisée :P

public abstract class SectionListAdapter extends BaseAdapter
{
   private SparseArray sectionRows; // cache section an row for a
   // position in the ListView
   private int[] rowCounts; // cache row count for a section

   public SectionListAdapter()
   {
       super();

       this.sectionRows = new SparseArray();
       this.updateRowCount();
   }

   public void notifyDataSetChanged()
   {
       this.sectionRows.clear();
       this.updateRowCount();

       super.notifyDataSetChanged(); // notify after clear
   }

   public final int getCount()
   {
       int count = 0;

       int sectionCount = this.getSectionCount();

       for (int section = 0; section < sectionCount; section++)
       {
           count += this.getRowCount(section);
       }

       return count;
   }

   public final Object getItem(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       Object o = this.getItem(sectionRow[0], sectionRow[1]);

       return o;
   }

   public final long getItemId(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       long id = this.getItemId(sectionRow[0], sectionRow[1]);

       return id;
   }

   public final View getView(int position, View convertView, ViewGroup parent)
   {
       int[] sectionRow = this.getSectionRow(position);

       convertView = this.getView(sectionRow[0], sectionRow[1], convertView, parent);

       return convertView;
   }

   public final int getItemViewType(int position)
   {
       int[] sectionRow = this.getSectionRow(position);

       int itemViewType = this.getItemViewType(sectionRow[0], sectionRow[1]);

       return itemViewType;
   }

   public final View getDropDownView(int position, View convertView, ViewGroup parent)
   {
       int[] sectionRow = this.getSectionRow(position);

       convertView = this.getDropDownView(sectionRow[0], sectionRow[1], convertView, parent);

       return convertView;
   }

   // Return the section and the row for a position (and save in cache)
   private int[] getSectionRow(int position)
   {
       int[] sectionRow = this.sectionRows.get(position);

       if (sectionRow == null)
       {
           int p = position;
           int sectionCount = this.getSectionCount();

           for (int i = 0; i < sectionCount; i++)
           {
               int rowCount = this.rowCounts[i];

               if (p < rowCount)
               {
                   sectionRow = new int[] { i, p };

                   break;
               }

               p -= rowCount;
           }

           if (sectionRow == null)
           {
               sectionRow = new int[] { -1, -1 };
           }

           this.sectionRows.put(position, sectionRow);
       }

       return sectionRow;
   }

   // Update the row counts cache
   private void updateRowCount()
   {
       int sectionCount = this.getSectionCount();

       if (this.rowCounts == null || this.rowCounts.length != sectionCount)
       {
           this.rowCounts = new int[sectionCount];
       }

       for (int i = 0; i < sectionCount; i++)
       {
           this.rowCounts[i] = this.getRowCount(i);
       }
   }

   // Return number of section
   // Don't forget to override getViewTypeCount()
   // SHOULD ALWAYS RETURN THE SAME NUMBER !!!
   public abstract int getSectionCount();

   // Return number of row for a section
   public abstract int getRowCount(int section);

   // Return an item for a section and a row
   public abstract Object getItem(int section, int row);

   // Return an item id for a section and a row
   public abstract long getItemId(int section, int row);

   // Return a view type for a section and a row
   public abstract int getItemViewType(int section, int row);

   // Return a view for a section and a row
   public abstract View getView(int section, int row, View convertView, ViewGroup parent);

   // ???
   public View getDropDownView(int section, int row, View convertView, ViewGroup parent)
   {
       return convertView;
   }
}

pour l'avoir utilisé, je la trouve super pratique pour réaliser des ListView assez complexes

Lien vers le commentaire
Partager sur d’autres sites

  • 2 years later...

Rejoignez la conversation

Vous pouvez poster maintenant et vous enregistrez plus tard. Si vous avez un compte, connectez-vous maintenant pour poster.

Invité
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...