Créer un BaseAdapter personnalisé réutilisable


Introduction à cette section :

Comme le titre l'indique, cette section vous présente la construction d'un BaseAdapter personnalisé réutilisable. Nous impliquons souvent ListView. GridView et d'autres contrôles Adapter vous obligent à écrire vous-même une autre classe BaseAdapter, ce qui est très gênant. Pour un autre exemple, si nous voulons afficher deux ListViews sur une seule interface, nous avons également besoin de deux BaseAdapters... Les programmeurs aiment être paresseux. Dans cette section, nous allons écrire une classe BaseAdapter personnalisée réutilisable~


1 Commençons par la changer petit à petit :

Tout d'abord. , nous collons le BaseAdapter personnalisé écrit dans la section précédente. Nous le mettrons à niveau plus tard

.
/**
 * Créé par Jay le 2015/9/21 0021.
 */
public class MyAdapter étend BaseAdapter {

    private Context mContext;
    private LinkedList<Data> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<Data> mData, Context mContext) {
        this.mData = mData;
        this. mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
public Object getItem(int position) {
        return null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
             convertView = LayoutInflater.from( mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
         } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
holder.txt_content.setText(mData.get(position).getContent());
return convertView;
}

//Ajouter un élément
public void add(Data data) {
if (mData == null) {
mData = new LinkedList<>();
}
mData.add(data);
notifyDataSetChan ged();
}

//Ajouter un élément à une position spécifique
public void add(int position,Data data){
if (mData == null) {
mData = new LinkedList<> ( );
}
       mData.add(position, data); if(mData ! = null) {
mData.remove(data);
}
notifyDataSetChanged();
}

public void delete(int position) {
If(mData ! = null) {
mData.remove(position);
}
notifyDataSetChanged();
}

public void clear() {
if(mData != null ) {
mData.clear();
}
notifyDataSetChanged();
}

classe privée ViewHolder {
ImageView img_icon;
TextView txt_content;
}

}


Mise à niveau 1 : définir Entity sur générique

D'accord, après tout, les classes d'entités Entitiy que nous transmettons peuvent être toutes sortes de bizarreries, comme Person, Book, Wether, etc., donc nous Définissez Entity sur générique, le code modifié est le suivant :

<pre>
classe publique MyAdapter<T> extends BaseAdapter {

    private Context mContext;
    private LinkedList<T> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<T> mData, Context mContext) {
        this.mData = mData;
        this. mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
public Object getItem(int position) {
        return null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
             convertView = LayoutInflater.from( mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
         } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
holder.txt_content.setText(mData.get(position).getContent());
return convertView;
}

//Ajouter un élément
public void add(T data) {
if (mData == null) {
mData = new LinkedList<>();
}
mData.add(data);
notifyDataSetChan ged();
}

//Ajouter un élément à une position spécifique
public void add(int position,T data){
if (mData == null) {
mData = new LinkedList<> ( );
}
       mData.add(position, data); if(mData ! = null) {
mData.remove(data);
}
notifyDataSetChanged();
}

public void delete(int position) {
If(mData ! = null) {
mData.remove(position);
}
notifyDataSetChanged();
}

public void clear() {
if(mData != null ) {
mData.clear();
}
notifyDataSetChanged();
}

classe privée ViewHolder {
ImageView img_icon;
TextView txt_content;
}

}

D'accord, ce que nous avons fait ci-dessus, c'est simplement de changer le type de données en un T générique !


Mise à niveau 2 : Mise à niveau de la classe ViewHolder :

Jetons d'abord un coup d'œil à ce que notre ViewHolder faisait auparavant ? Réponse : findViewById, définissez l'état du contrôle ; Ensuite, nous souhaitons écrire l'essentiel de la logique de la méthode getView() dans la classe ViewHolder sur la base de cette opération. Ce que ce ViewHolder doit faire :

  • Définir une méthode pour trouver des contrôles. Notre idée est d'exposer les méthodes publiques et de les transmettre lors de l'appel de la méthode. Contrôlez l'identifiant et définissez le contenu, tel que le texte de paramètre TextView : public ViewHolder setText(int id, CharSequence text){text settings>
  • Déplacez la partie de réutilisation de convertView ici, vous devez alors passer un objet contextuel, nous devons obtenir Toutes les pièces sont écrites dans le constructeur !
  • Écrivez un tas de méthodes de configuration (publiques), telles que la définition de la taille du texte, de la couleur, de l'arrière-plan de l'image, etc. !

D'accord, transformons notre classe ViewHolder étape par étape


1) Paramètres et méthodes de construction pertinents :

public static class ViewHolder {

private SparseArray<View> //Vue de stockage dans l'élément de ListView
élément de vue privé ; //Storage convertView
position int privée ;        // Curseur
contexte privé context; //Contexte contextuel

//Méthode de construction pour terminer l'initialisation associée
private ViewHolder (Contexte contextuel, parent ViewGroup, int layoutRes) {
mView s = new SparseArray <();
this.context = context;
View convertView = LayoutInflater.from(context).inflate(layoutRes, parent,false);
convertView.setTag (this = convertView;
}

ImageView img_icon;
TextView txt_content;
}

2) Lier ViewHolder et Item

Sur la base de ce qui précède, nous ajoutons une autre méthode de liaison

//Lier ViewHolder et item<🎜 ​​>liaison publique statique ViewHolder (Contexte contextuel, View convertView, ViewGroup parent,
                                                                                                   ViewHolder                                                 
holder = new ViewHolder(context, parent, layoutRes);
} else {
holder = (ViewHolder) convertView.getTag();
holder.item = convertView;
}
holder.position = position;
returnholder;
}


3) Obtenez le contrôle enregistré dans la collection selon l'identifiant

public <T extends View> T getView( int id) {

T t = (T) mViews.get(id);
if( t == null) {
t = (T) item.findViewById(id);
mViews .put(id, t);
}
return t;
>

4) 接着我们再定义一堆暴露出来的方法

/**
* Obtenez l'entrée actuelle
*/
public View getItemView() {
    retourner l'élément ;
}

/**
* Obtenir le lieu d'entrée
*/
public int getItemPosition() {
    return position;
}

/**
* Définir le texte
*/
public ViewHolder setText(int id, CharSequence text) {
    View view = getView(id);
    if(view instanceof TextView) {
        ((TextView) view).setText(text);
    }
    retourner ceci ;
}

/**
* Définir l'image
*/
public ViewHolder setImageResource(int id, int drawableRes) {
    View view = getView(id) ;
    if(view instanceof ImageView) {
        ((ImageView) view).setImageResource(drawableRes);
    } else {
        view.setBackgroundResource(drawableRes);
    }
    return this;
}


/**
* Mettre en place la surveillance des clics
*/
public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
    getView(id).setOnClickListener(listener );
    retourner ceci ;
}

/**
* Paramètres visibles
*/
public ViewHolder setVisibility(int id, int visible) {
    getView(id).setVisibility( visible);
    retourner this;
}

/**
* Définir des balises
*/
public ViewHolder setTag(int id, Object obj) {
    getView(id).setTag (obj);
    retourner ceci ;
}

//其他方法可自行扩展

D'accord, la transformation et la mise à niveau de ViewHolder sont terminées~


Mise à niveau 3 : définir une méthode abstraite pour terminer la liaison de ViewHolder et de l'ensemble de données Data

public abstract void bindView(ViewHolder holder, T obj);

Nous créons un nouveau BaseAdapter Quand, implémentez simplement cette méthode. De plus, n'oubliez pas de personnaliser notre. Le BaseAdapter est changé en abstrait !


Mise à niveau 4 : Modifier le contenu de la partie getView()

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
            , position);
    bindView(holder,getItem(position));
    return holder.getItemView();
}

2 Après la mise à niveau, nous écrivons du code pour en faire l'expérience :

Nous voulons implémenter le rendu :

1.png

Il y a deux listes ci-dessus avec des mises en page différentes, mais je n'utilise qu'une seule classe BaseAdapter pour obtenir l'effet ci-dessus !

Le code clé est le suivant :

MainActivity.java :

<App > myAdapter1 = null;
    private MyAdapter<Book> myAdapter2 = null;
    liste privée<App> mData1 = null;
    Liste privée<Livre> mData2 = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        init();

    }

    private void init() {

        list_book = (ListView) findViewById(R.id.list_book);
        list_app = (ListView) findViewById(R.id.list_app);

        //数据初始化
        mData1 = new ArrayList<App>();
        mData1.add(nouvelle application( R.mipmap.iv_icon_baidu,"百度"));
        mData1.add(nouvelle App(R.mipmap.iv_icon_douban,"豆瓣"));
        mData1.add(nouvelle App(R.mipmap.iv_icon_zhifubao, "支付宝"));

        mData2 = new ArrayList<Book>();
        mData2.add(new Book("《第一行代码Android》","郭霖"));


        //Adapter初始化
        myAdapter1 = new MyAdapter<App>((ArrayList)mData1,R.layout.item_one) {
            @Override
            public void bindView(ViewHolder holder, App obj) {
                holder.setImageResource(R.id.img_icon,obj.getaIcon());
                holder.setText(R.id.txt_aname,obj.getaName()) ;
            }
        };
        myAdapter2 = new MyAdapter<Book>((ArrayList)mData2,R.layout.item_two) {
            @Override
            public void bindView (ViewHolder holder, Book obj ) {
                holder.setText(R.id.txt_bname,obj.getbName());
               holder.setText(R.id.txt_bauthor,obj.getbAuthor());
             >
        } ;

        //ListView设置下Adapter:
        list_book.setAdapter(myAdapter2);
        list_app.setAdapter(myAdapter1);

    }


>

Le BaseAdapter réutilisable que nous avons écrit est utilisé comme décrit ci-dessus~


3. Téléchargement d'un exemple de code :

ListViewDemo4.zip

post Téléchargez le dernier MyAdapter écrit. classe, qui peut être étendue selon vos propres besoins :

MyAdapter.java:

/**
 * Créé par Jay le 2015/9/22 0022.
 */
classe abstraite publique MyAdapter<T> extends BaseAdapter {

    private ArrayList<T> mData;
    private int mLayoutRes;           //布局id


    public MyAdapter() {
    }

    public MyAdapter(ArrayList<T> mData, int mLayoutRes) {
        this.mData = mData;
        this.mLayoutRes = mLayoutRes;
    }

    @Override
    public int getCount() {
        return mData != null ? mData.size() : 0;
    }

    @Override
    public T getItem(int position) {
        return mData.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, View Group parent) {
        ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
               , position);
        bindView(holder, getItem(position));
        return holder.getItemView() ;
    }

    public abstract void bindView(ViewHolder holder, T obj);

    //添加一个元素
    public void add(T data) {
        si ( mData == null) {
            mData = new ArrayList<>();
             mData.add(data);
        notifyDataSetChanged();
    }

    //往特定位置,添加一个元素
    public void add(int position, T data) {
        if (mData == null) {
             mData = nouveau ArrayList<> ;();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }

    public void remove(T-data) {
        if ( mData != null) {
            mData.remove(data);
        >
        notifyDataSetChanged();
    }

    public void remove(int position) {
        si ( mData != null) {
            mData.remove(position);
        >
        notifyDataSetChanged();
    }

    public void clear() {
        if (mData ! = null) {
            mData.clear();
         >
        notifyDataSetChanged();
    }


    classe statique publique ViewHolder {

        privé SparseArray< ;Afficher> mVues ;   //存储ListView 的 item中的View
        élément de vue privée ;                  //存放convertView
        private int position ;               //游标
        contexte privé ;            //Context上下文

        //构造方法,完成相关初始化
        private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
            mViews = new SparseArray<>();
            this.context = context;
            View convertView = La youtInflater.from(context).inflate( layoutRes, parent, false);
            convertView.setTag(this);
            item = convertView;
        }

        //绑定ViewHolder与item
        public static ViewHolder bind (Contexte context, View convertView, ViewGroup parent,
                                     int layoutRes, int position) {
            ViewHolder holder ;
            if (convertView == null) {
                holder = new ViewHolder(context, parent, layoutRes);

            holder.position = position;
            retour holder;
        }

        @SuppressWarnings("unchecked")
        public <T étend View> T getView(int id) {
            T t = (T) mViews.get(id);
            if (t == null) {
                t = (T) item.findViewById(id);
                mViews.put(id, t);
            }
             retourner t ;
         }


        /***
         * Obtenir l'entrée actuelle
          */
        public View getItemView() {
            retourner l'élément;
        }

        /**
* Obtenir le lieu d'entrée
*/
        public int getItemPosition() {
            return position;
        }

        /**
*Définir le texte
*/
       public ViewHolder setText(int id, CharSequence text) {
            Afficher view = getView(id);
            if (view instanceof TextView) {
                ((TextView) view).setText(text);
             }
            return this;
        }

        /**
                                                           Définir la photo <🎜                  */
        public ViewHolder setImageResource(int id, int drawableRes) {
            View view = getView(id);
            if (view instanceof ImageView) {
                ((ImageView) view).setImageResource(drawableRes);
            } else {
                view.setBackgroundResource(drawableRes);
            }
            retourner ce ;
        }


        /**
*Configurer la surveillance des clics
*/
        public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
            getView(id).setOnClickListener( auditeur);
> setVisibilité(visible);
            retourner ceci ;
        }

        /**
* Les paramètres sont visibles
*/
        public ViewHolder setTag(int id, Object obj) {
            getView (id).setTag(obj);
            retourner ceci ;
        }

        //其他方法可自行扩展

    }

}


Résumé de cette section :

Cette section présente comment implémenter un BaseAdapter réutilisable. Bien sûr, vous pouvez l'utiliser en fonction de. Modifiez en fonction de vos propres besoins, comme définir des images réseau de manière asynchrone, etc. Le code modifié est écrit en référence à la vidéo de Hong Yang : Lien vidéo : Android - Création d'un adaptateur universel. De plus, j'ai rencontré quelques problèmes lors de l'écriture proprement dite. Merci beaucoup Berial (B God) pour votre patience~2.jpgありがとうございます~<🎜. >