ListView的适配器笔记

继承BaseAdapter ,
getView方法:
Get a View that displays the data at the specified position in the data set

getView 方法需要返回一个view 提供给对应的列表项用来显示
一般的做法是, 先根据指定的position获取数据 , 然后通过inflater创建view或复用convertView,
将获取到的数据设置显示在view中, 最后返回该view

一般的写法是
1. getItem(positoin) 获取数据
2. convertView是否存在,
不存在则 -> inflater获取该列表项的 view 赋值给convertView
-> 然后convertView.findById 将子控件一个个都赋值给viewHolder
-> convertView.setTag(viewHolder);
存在则 -> view = convertView
-> viewHolder = (ViewHolder)convertView.getTag() ;
3. 使用第一步获取的数据, 设置到viewHolder下的控件中 ,比如 : viewHolder.控件.setText(“数据”) 等等来设置view
4. return语句, 返回convertView, 这个view 就是第二步里面inflate的返回值, 或者是将已存在converView直接返回 …

列表项item不同类型, 需要分别加载不同的布局文件时, 需要一个类型参数,每一个类型参数对应一个列表项的view,
当我们需要加载不同的列表项的时候, 就需要用到该类型参数,
这样, 比一般情况下需要多出两个需要重载的方法 , getViewTypeCount 和 getItemViewType
getViewTypeCount: 该方法返回的是getView方法将创建的view的类型总数 , 我们自定义的类型总数
getItemViewType: 该方法返回getView将创建的View的类型值, 类型值

这个两个需要重写的方法比较简单, 主要的不同在getView方法中, 相当于需要对每个列表项创建一个viewHolder,
使用两个参数的setTag方法 , 然后在使用绑定数据显示的时候, 需要使用switch来使用viewHolder.

按数据来设置viewHolder中的控件的显示 , 数据可以保存在成员变量中, 然后定义一个方法比如setData 在外面给成员变量赋值
然后这里就不用getItem取数据了 , 直接读取成员变量 然后设置viewHolder显示控件
bindViewData , 这个方法里, 必须要用switch 根据不同的type来对ViewHolder进行操作 , 否则就会提示空指针
上面我们在buildHolder里面对所有控件进行了初始化, 那么在绑定数据的时候为什么还会提示空指针呢???
因为我们每个item的布局文件不一样, 因此 对每一个布局文件其实都需要一个holder
只是我们为了方便在buildHolder中把所有子控件初始化写在一起 ,但是每次系统读取的时候其实都只能获取到该类型列表项下的控件
其他控件看起来是赋值过的, 但实际上都是null .
上面的代码中, switch 分支中分别加载一个布局文件, 都运行了一次setTag , 就相当于每个switch都分支都设置了一个holder
但这个holder中, 只有对应该item的部分控件是被初始化了的, 其他的赋值语句findById实际上都是返回的null
convertView.setTag(R.drawable.ic_launcher + itemType, viewHolder);
然后通过type取出不同的holder
viewHolder = (ViewHolder) convertView.getTag(R.drawable.ic_launcher + itemType);
所以千万不能看到buildHolder中 对所有布局文件下的控件都赋值了, 就认为可以随意使用, 其实实际上是对每个item都对应一个holder,
初始化和读取的时候都是按类型获取holder, 所以最后在绑定数据,设置view的时候必须判断类型使用switch,只操作该类型下的holder控件, 否则报空指针错误

import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class DifferentTypeItemAdapter extends BaseAdapter {
    private static final int TYPE_A = 0;
    private static final int TYPE_B = 1;
    private static final int TYPE_C = 2;
    private static final int TYPE_D = 3;

    private LayoutInflater mLayoutInflater;
    private List<Integer> mTypes;

    public DifferentTypeItemAdapter(Context context) {
        mLayoutInflater = LayoutInflater.from(context);

        mTypes = new ArrayList<Integer>();
        mTypes.add(TYPE_A);
        mTypes.add(TYPE_B);
        mTypes.add(TYPE_C);
        mTypes.add(TYPE_D);

    }

    // 一般的ListView就不需要复写这个方法, item的类型不同加载不同的布局文件时,
    // 需要一个类型参数,每一个类型参数对应一个item的view
    // 需要复写该方法getViewTypeCount , 该方法返回的是getView方法将创建的view的类型总数
    @Override
    public int getViewTypeCount() {
        return mTypes.size();
    }

    // getItemViewType 复写该方法返回getView将创建的View的类型值
    // 加载不同的item布局文件相比普通的adapter只需要多出这两个type相关的方法即可, 主要工作还是在getView里面
    @Override
    public int getItemViewType(int position) {

        if (position < mTypes.size())
            return mTypes.get(position);
        return super.getItemViewType(position);
    }

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

    @Override
    public Object getItem(int position) {
        return mTypes.get(position);
    }

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

/*   getView 根据指定的position获取数据 , 然后通过inflater创建view或复用view,
     并对view设置获取的数据进行显示 再返回该view
     一般的写法是
     1. getItem(positoin) 获取数据
     2. convertView是否存在,
     不存在则 -> inflater获取该列表项的 view 赋值给convertView 
            -> 然后convertView.findById  将子控件一个个都赋值给viewHolder 
            -> convertView.setTag(viewHolder);
     存在则 -> view = convertView 
            -> viewHolder = (ViewHolder)convertView.getTag() ;
     3. 使用第一步获取的数据, 设置到viewHolder下的控件中 ,比如 :  viewHolder.控件.setText("数据")  等等来设置view
     4. return语句, 返回convertView, 这个view 就是第二步里面inflate的返回值, 或者是将已存在converView直接返回 ... 
 */
    // Get a View that displays the data at the specified position in the data set

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        int itemType = getItemViewType(position);
        ViewHolder viewHolder;

        if (convertView == null) {
            switch (itemType) {
            case TYPE_A:
                convertView = mLayoutInflater.inflate(R.layout.type_a, parent,
                        false);
                break;
            case TYPE_B:
                convertView = mLayoutInflater.inflate(R.layout.type_b, parent,
                        false);
                break;
            case TYPE_C:
                convertView = mLayoutInflater.inflate(R.layout.type_c, parent,
                        false);
                break;
            case TYPE_D:
                convertView = mLayoutInflater.inflate(R.layout.type_d, parent,
                        false);
                break;
            }
            viewHolder = buildHolder(convertView);
            convertView.setTag(R.drawable.ic_launcher + itemType, viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag(R.drawable.ic_launcher + itemType);

        }

        bindViewData(viewHolder, position);

        return convertView;
    }

    private ViewHolder buildHolder(View convertView) {
        ViewHolder holder = new ViewHolder();
        holder.viewA_1 = convertView.findViewById(R.id.a1);
        holder.viewA_2 = convertView.findViewById(R.id.a2);
        holder.viewA_3 = convertView.findViewById(R.id.a3);

        holder.viewB_1 = (ImageView) convertView
                .findViewById(R.id.b1);
        holder.viewB_2 = (TextView) convertView
                .findViewById(R.id.b2);
        holder.viewB_3 = (TextView) convertView.findViewById(R.id.b3);

        holder.viewC_1 = (ImageView) convertView.findViewById(R.id.c1);
        holder.viewC_2 = (TextView) convertView.findViewById(R.id.c2);
        holder.viewC_3 = (TextView) convertView.findViewById(R.id.c3);

        holder.viewD_1 = convertView.findViewById(R.id.d1);
        holder.viewD_2 = convertView.findViewById(R.id.d2);
        holder.viewD_3 = convertView.findViewById(R.id.d3);
        return holder;
    }

    /**
     * 按数据来设置viewHolder中的控件的显示 , 数据可以保存在成员变量中, 然后定义一个方法比如setData 在外面给成员变量赋值
     * 然后这里就不用getItem取数据了 , 直接读取成员变量 然后设置viewHolder显示控件
     * bindViewData , 这个方法里, 必须要用switch 根据不同的type来对ViewHolder进行操作 , 否则就会提示空指针
     * 上面我们在buildHolder里面对所有控件进行了初始化,    那么在绑定数据的时候为什么还会提示空指针呢???
     * 因为我们每个item的布局文件不一样, 因此 对每一个布局文件其实都需要一个holder 
     * 只是我们为了方便在buildHolder中把所有子控件初始化写在一起 ,但是每次系统读取的时候其实都只能获取到该类型列表项下的控件
     * 其他控件看起来是赋值过的, 但实际上都是null .
     * 上面的代码中, switch 分支中分别加载一个布局文件, 都运行了一次setTag , 就相当于每个switch都分支都设置了一个holder
     * 但这个holder中, 只有对应该item的部分控件是被初始化了的, 其他的赋值语句findById实际上都是返回的null
     * convertView.setTag(R.drawable.ic_launcher + itemType, viewHolder);
     * 然后通过type取出不同的holder 
     * viewHolder = (ViewHolder) convertView.getTag(R.drawable.ic_launcher + itemType);
     * 
     * 所以千万不能看到buildHolder中 对所有布局文件下的控件都赋值了, 就认为可以随意使用, 其实实际上是对每个item都对应一个holder, 
     * 初始化和读取的时候都是按类型获取holder, 所以最后在绑定数据,设置view的时候必须判断类型使用switch,只操作该类型下的holder控件, 否则报空指针错误
     * 
     */

    private void bindViewData(ViewHolder viewHolder, int position) {

        switch (getItemViewType(position)) {
        case TYPE_A:
            // TYPE A
            ImageView iv = (ImageView) viewHolder.viewA_1
                    .findViewById(R.id.iv);
            ;
            iv.setImageResource(R.drawable.ic_cloudy_big);
            ImageView iv2 = (ImageView) viewHolder.viewA_2
                    .findViewById(R.id.iv2);
            iv2.setImageResource(R.drawable.icig);
            ImageView iv3 = (ImageView) viewHolder.viewA_3
                    .findViewById(R.id.iv3);
            iv3.setImageResource(R.drawable.hurht);
            break;
        case TYPE_B:
            // TYPE B
            viewHolder.viewB_1.setImageResource(R.drawable.icig);
            viewHolder.viewB_2.setText("testtest");
            viewHolder.viewB_3.setText("datatext3");
            break;
        case TYPE_C:
            // TYPE C
            viewHolder.viewC_1
                    .setImageResource(R.drawable.b0);
            viewHolder.viewC_2.setText("ttttt");
            viewHolder.viewC_3.setText(222 + "");
            break;
        case TYPE_D:
            // TYPE D
            ImageView ImageViewD_1 = (ImageView) viewHolder.viewD_1
                    .findViewById(R.id.indv);
            ImageViewD_1.setImageResource(R.drawable.ic_lid);
            ImageView ImageViewD_2 = (ImageView) viewHolder.viewD_2
                    .findViewById(R.id.indv);
            ImageViewD_2.setImageResource(R.drawable.ic_lia);
            ImageView ImageViewD_3 = (ImageView) viewHolder.viewD_3
                    .findViewById(R.id.indv);
            ImageViewD_3.setImageResource(R.drawable.ics);
        }
    }

    /**
     * 根据每个类型Item对应的布局文件中的控件定义ViewHolder
     */

    private static final class ViewHolder {
        // TYPE_A
        View viewA_1;
        View viewA_2;
        View viewA_3;
        // TYPE_B
        ImageView viewB_1;
        TextView viewB_2;
        TextView viewB_3;
        // TYPE_C
        ImageView viewC_1;
        TextView viewC_2;
        TextView viewC_3;
        // TYPE_D
        View viewD_1;
        View viewD_2;
        View viewD_3;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值