listview的重要属性viewtype,实现多类型item样式
来源:互联网 发布:linux session 编辑:程序博客网 时间:2024/05/17 01:08
listview作为传统展示大量数据的基本控件,其回收能力是核心。考虑到数据并不一定是单一的样式,因此,view type使得多样式的列表结构变得简单清晰。
直接贴代码,再分析。
哦,在这之前,先效果图:
代码很简单,主要就是在adapter里面重写
getViewTypeCount()
getItemViewType(int position)这两个方法。MultiStyleListAdapter.java:
<pre name="code" class="java">public class MultiStyleListAdapter extends AbstractListAdapter<Object> { private Class[] dataClasses;@Overridepublic View getView(int position, View view, ViewGroup parent) {int viewType=getItemViewType(position);if (viewType==0) {view = getStyle1View(position, view, parent);}else if (viewType==1) {view = getStyle2View(position, view, parent);} else if(viewType==2){view = getStyle3View(position, view, parent);}else if(viewType==3){view=getStyle4View(position, view, parent);}return view;}public MultiStyleListAdapter(Context context) {// TODO Auto-generated constructor stubsuper(context);dataClasses=new Class[]{Data1.class,Data2.class,Data3.class,Data4.class};} /** * 注意返回的类型: * 如果只有1种布局类型,那么返回的type是0; * 如果2种类型,必须是0,1 * 如果3种类型,必须是0,1,2 * 。。。。 * 依次类推 * @param position 根据position返回对应位置的视图类型 * @return */@Overridepublic int getItemViewType(int position) {// TODO Auto-generated method stubObject object=getItem(position);for(int i=0,size=dataClasses.length;i<size;i++){if(object.getClass()== dataClasses[i]){return i;}}return 0;} /** * @return 返回值是,布局种类总数 */@Overridepublic int getViewTypeCount() {// TODO Auto-generated method stubreturn dataClasses.length;}private View getStyle1View(final int position, View convertView,ViewGroup parent) {final Styly1ViewHolder holder;if (convertView == null) {convertView = mInflater.inflate(R.layout.item_style_1, null);holder = new Styly1ViewHolder(convertView);convertView.setTag(holder);} else {holder = (Styly1ViewHolder) convertView.getTag();}final Data1 item=(Data1)mList.get(position);holder.tvIndex.setText("index="+position);holder.content.setText(item.content);return convertView;}private View getStyle2View(final int position, View convertView, ViewGroup parent) {final Styly2ViewHolder holder;if (convertView == null) {convertView = mInflater.inflate(R.layout.item_style_2, null);holder = new Styly2ViewHolder(convertView);convertView.setTag(holder);} else {holder = (Styly2ViewHolder) convertView.getTag();}final Data2 item=(Data2)mList.get(position);holder.tvIndex.setText("index="+position);holder.pic.setImageResource(item.img);return convertView;}private View getStyle3View(final int position, View convertView, ViewGroup parent) {final Styly3ViewHolder holder;if (convertView == null) {convertView = mInflater.inflate(R.layout.item_style_3, null);holder = new Styly3ViewHolder(convertView);convertView.setTag(holder);} else {holder = (Styly3ViewHolder) convertView.getTag();}final Data3 item=(Data3)mList.get(position);holder.tvIndex.setText("index="+position);holder.pic1.setImageResource(item.img1);holder.pic2.setImageResource(item.img2);holder.pic3.setImageResource(item.img3);return convertView;}private View getStyle4View(final int position, View convertView, ViewGroup parent) {final Styly4ViewHolder holder;if (convertView == null) {convertView = mInflater.inflate(R.layout.item_style_4, null);holder = new Styly4ViewHolder(convertView);convertView.setTag(holder);} else {holder = (Styly4ViewHolder) convertView.getTag();}final Data4 item=(Data4)mList.get(position);holder.tvIndex.setText("index="+position);holder.checkBox.setText(item.content);holder.checkBox.setChecked(item.isChecked);return convertView;}class Styly1ViewHolder {TextView tvIndex;TextView content;public Styly1ViewHolder(View root){content=(TextView)root.findViewById(R.id.content);tvIndex=(TextView)root.findViewById(R.id.index);}}class Styly2ViewHolder {TextView tvIndex;ImageView pic;public Styly2ViewHolder(View root){pic=(ImageView)root.findViewById(R.id.content);tvIndex=(TextView)root.findViewById(R.id.index);}}class Styly3ViewHolder {TextView tvIndex;ImageView pic1;ImageView pic2;ImageView pic3;public Styly3ViewHolder(View root){pic1=(ImageView)root.findViewById(R.id.img1);pic2=(ImageView)root.findViewById(R.id.img2);pic3=(ImageView)root.findViewById(R.id.img3);tvIndex=(TextView)root.findViewById(R.id.index);}}class Styly4ViewHolder {TextView tvIndex;CheckBox checkBox;public Styly4ViewHolder(View root){checkBox=(CheckBox)root.findViewById(R.id.checkbox);tvIndex=(TextView)root.findViewById(R.id.index);}}}
demo用了4个样式,分别对应4个viewholder,定义4个数据模型,data1,data2,data3,data4,根据viewtype来实例化或复用对应view,并绑定对应数据。
注意getViewType返回值,必须从0开始,依次增大。否则要抛ArrayIndexOutOfBoundsException异常,原因文章后面分析。
AbstractListAdapter.java 继承至BaseAdapter,只是对它进行部分重写和封装,以及使用泛型后的一个基类。
还是把贴出来吧,免得对新手造成疑惑。
public abstract class AbstractListAdapter <T> extends BaseAdapter { protected List<T> mList; protected Context mContext; private AdapterView mListView; protected LayoutInflater mInflater; public AbstractListAdapter(Activity context) { this.mContext = context; mInflater = LayoutInflater.from(context); } public AbstractListAdapter(Context context) { mContext=context; mInflater = LayoutInflater.from(context); } @Override public Object getItem(int i) { return mList == null ? null : mList.get(i); } @Override public int getCount() { return mList == null ? 0 : mList.size(); } @Override public long getItemId(int i) { return i; } @Override public abstract View getView(int i, View view, ViewGroup viewGroup); public void setList(List<T> list) { this.mList = list; } public List<T> getList() { return this.mList; } public AdapterView getListView(){ return mListView; } public void setListView(AdapterView listView){ mListView = listView; } public Context getContext(){ return mContext; } public void setList(T[] list){ if (list == null) return; ArrayList<T> arrayList = new ArrayList<T>(list.length); for (T t : list) { arrayList.add(t); } setList(arrayList); } public void clear() { if (mList != null && mList.size() > 0){ mList.clear(); } }}
然后添加示例数据:
MainActivity.java
public class MainActivity extends AppCompatActivity { private ListView mListview; private MultiStyleListAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListview=(ListView)findViewById(R.id.listview); mAdapter=new MultiStyleListAdapter(this); mListview.setAdapter(mAdapter); createData(); } private void createData(){ List<Object> dataAll=new ArrayList<>(); dataAll.add(new Data1("打开链接快乐大脚")); dataAll.add(new Data2(R.drawable.img1)); dataAll.add(new Data2(R.drawable.img2)); dataAll.add(new Data1("萨达姆分,吗,")); dataAll.add(new Data3(R.drawable.img3,R.drawable.img4,R.drawable.img5)); dataAll.add(new Data4("昂啥呢",true)); dataAll.add(new Data3(R.drawable.img6,R.drawable.img7,R.drawable.img8)); dataAll.add(new Data1("萨达姆分,吗,")); dataAll.add(new Data2(R.drawable.img9)); dataAll.add(new Data2(R.drawable.img10)); dataAll.add(new Data2(R.drawable.img11)); dataAll.add(new Data1("暗红色的尽快和圣诞节快放假")); dataAll.add(new Data1("跨境开理发店了")); dataAll.add(new Data1("1434")); dataAll.add(new Data1("地方")); dataAll.add(new Data1("主线程执行")); dataAll.add(new Data4("ansdklma,sdm,",true)); dataAll.add(new Data4("撒角度看",true)); dataAll.add(new Data3(R.drawable.img12,R.drawable.img13,R.drawable.img14)); dataAll.add(new Data1("暗红色的尽快和圣诞节快放假")); dataAll.add(new Data1("13123123")); dataAll.add(new Data1("154667678")); mAdapter.setList(dataAll); mAdapter.notifyDataSetChanged(); }}
好了,代码贴完,可以开始分析了。
大家都知道listview,gridview都是继承至abslistview。它的回收能力来自于abslistview。
滚动时,超出屏幕的视图会被扔进回收站,当listview判定出即将有item进入屏幕时,又会从回收站里面把视图拿出来重用,当然,前提是回收站里有满足要求的视图。否则会创建新实例。这部分源码不是重点,有兴趣的同学自行查看源码或相关文档。
RecycleBin,这就是这个回收站,在listview实例创建时而被创建。其中有几个比较重要的成员变量
View[] mActiveViews 存的是处于屏幕里的view
ArrayList<View>[] mScrapViews; 存的是所有废弃的view,它就是我们要说的重点。这个数组的每个元素都是一个view的集合,其实也就是每个类型一个集合。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<View>[] scrapViews = new ArrayList[viewTypeCount]; for (int i = 0; i < viewTypeCount; i++) { scrapViews[i] = new ArrayList<View>(); } mViewTypeCount = viewTypeCount; mCurrentScrap = scrapViews[0]; mScrapViews = scrapViews;}//从垃圾堆里重新取得viewprivate View retrieveFromScrap(ArrayList<View> 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;}}
listview里的每个视图就是在这个方法中被创建的absListView.obtainView(int position, boolean[] isScrap){......//从回收站重新取出对应type的viewfinal View scrapView = mRecycler.getScrapView(position);//再传入getview里重新绑定数据。final View child = mAdapter.getView(position, scrapView, this);......}absListView的obtainview方法创建或者复用回收站里面的viewabsListView的trackMotionScroll--->mRecycler.addScrapView(child, position);trackMotionScroll滚动时会被调用,这里面判断哪些view被废弃。所以listview滚动时,判定哪些view超出屏幕,超出就被放入回收站里,等又需要view的时候,listview根据viewtype类型从回收站里取出来复用,并回调到adapter的getview方法里面,从而达到多类型复用的效果demo源码:https://github.com/qinzhen308/ListviewExploreDemo或http://download.csdn.net/detail/qinzhen308/9603718
0 0
- listview的重要属性viewtype,实现多类型item样式
- ListView的多种ViewType
- ListView中有不同的ViewType,它的convertView实现
- Android 多种ViewType的ListView
- Adapter类型控件之ListView Item多布局的实现
- listView的重要属性
- ListView的重要属性
- Listview的重要属性
- ListView多类型Item
- listview的多item类型的优化
- Android listview设置多个不同的item样式
- 【Android界面实现】listview控件的一些重要属性整理
- 【Android界面实现】listview控件的一些重要属性整理
- Android ListView 重要的属性
- listview重要的几个属性
- listView 几个重要的属性
- listview的几个重要属性
- android listview重要的属性
- js作用域
- 激励自我!向着大牛的背影进发!
- camera otp
- 数据结构实验之查找一:二叉排序树
- MySQL---数据库从入门走向大神系列(十四)-ComboPooledDataSource(C3P0连接池配置)
- listview的重要属性viewtype,实现多类型item样式
- leetcode Trapping Rain Water
- 用纯JAVA语言编程读取MAC地址的实现
- JavaScript 实现类似Java Map对象
- BCB编程规范
- java编程过程中的if语句
- VS的MFC项目生成不依赖运行时不依赖MFC的程序
- cocoapods:(-bash: pod: command not found) +( activesupport requires Ruby version >= ???)
- CodeForces 680B Bear and Finding Criminals(捉小偷)