继承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;
}
}