ListView作为传统展示大量数据的基本控件,其回收能力是核心。考虑到数据并不一定是单一的样式,因此,viewTpe使得多样式的列表结构变得简单清晰。
效果图:
代码:
代码很简单,主要就是在adapter里面重写
getViewTypeCount()
getItemViewType(int position)
这两个方法。
MultiStyleListAdapter.java:
public class MultiStyleListAdapter extends AbstractListAdapter
viewType分析
好了,代码贴完,可以开始分析了。
大家都知道ListView,GridView都是继承至AbsListView。它的回收能力来自于abslistview。
滚动时,超出屏幕的视图会被扔进回收站,当ListView判定出即将有item进入屏幕时,又会从回收站里面把视图拿出来重用,当然,前提是回收站里有满足要求的视图。否则会创建新实例。这部分源码不是重点,有兴趣的同学自行查看源码或相关文档。
RecycleBin,这就是这个回收站,在ListView实例创建时而被创建。其中有几个比较重要的成员变量
View[] mActiveViews 存的是处于屏幕里的view
ArrayList
RecycleBin.setViewTypeCount(int viewTypeCount)是在ListView的setAdapter里面被调用的,这时就会根据type的数量创建对应个数的view集合。
getScrapView()里以viewType取集合,所以,前面所说的adapter里面的getviewtype的返回值必须从0开始,且不间断的自然数。
class RecycleBin {
//根据viewtype的种类数量创建arraylist的数组
public void setViewTypeCount(int viewTypeCount) {
if (viewTypeCount < 1) {
throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
}
//noinspection unchecked
ArrayList[] scrapViews = new ArrayList[viewTypeCount];
for (int i = 0; i < viewTypeCount; i++) {
scrapViews[i] = new ArrayList();
}
mViewTypeCount = viewTypeCount;
mCurrentScrap = scrapViews[0];
mScrapViews = scrapViews;
}
//从垃圾堆里重新取得view
private View retrieveFromScrap(ArrayList scrapViews, int position) {
final int size = scrapViews.size();
if (size > 0) {
// See if we still have a view for this position or ID.
for (int i = 0; i < size; i++) {
final View view = scrapViews.get(i);
final AbsListView.LayoutParams params =
(AbsListView.LayoutParams) view.getLayoutParams();
if (mAdapterHasStableIds) {
final long id = mAdapter.getItemId(position);
if (id == params.itemId) {
return scrapViews.remove(i);
}
} else if (params.scrappedFromPosition == position) {
final View scrap = scrapViews.remove(i);
clearAccessibilityFromScrap(scrap);
return scrap;
}
}
final View scrap = scrapViews.remove(size - 1);
clearAccessibilityFromScrap(scrap);
return scrap;
} else {
return null;
}
}
//根据viewtype获取对应类型的view集合
View getScrapView(int position) {
final int whichScrap = mAdapter.getItemViewType(position);
if (whichScrap < 0) {
return null;
}
if (mViewTypeCount == 1) {
return retrieveFromScrap(mCurrentScrap, position);
} else if (whichScrap < mScrapViews.length) {
//以viewtype为下标取集合
return retrieveFromScrap(mScrapViews[whichScrap], position);
}
return null;
}
}
AbsListView.java:
//listview里的每个视图就是在这个方法中被创建的
View obtainView(int position, boolean[] isScrap){
......
//从回收站重新取出对应type的view
final View scrapView = mRecycler.getScrapView(position);
//再传入getview里重新绑定数据。
final View child = mAdapter.getView(position, scrapView, this);
......
}
AbsListView的obtainview方法创建或者复用回收站里面的view
absListView的trackMotionScroll()--->mRecycler.addScrapView(child, position);
trackMotionScroll()滚动时会被调用,这里面判断哪些view被废弃。
所以ListView滚动时,判定哪些view超出屏幕,超出就被放入回收站里,等又需要view的时候,listview根据viewType类型从回收站里取出来复用,并回调到adapter的getView()方法里面,从而达到多类型复用的效果。