前言
我們之前使用的 ListView ,其中的 Item 都是固定的一類數據,那麼如何實現類似微信聊天界面的佈局呢?即多個類型 Item 顯示在同一個 ListView 上。
實現方法
目前想到到方法有兩個:
- 讓每個 Item 的佈局都包含所有類型的元素然後通過隱藏的方法去組合出不同 Item
- 使用 Adapter 原生支持的多類型
由於方法一每次都需要 inflate 出所以類型的元素,再去隱藏,勢必會造成資源的浪費
因而本文使用的是方法二;該方法需要利用兩個函數
1)重寫 getViewTypeCount () – 該方法返回多少個不同的佈局
2)重寫 getItemViewType (int) – 根據 position 返回相應的 Item
具體實現
本文基於上一篇 打造通用 BaseAdapter,並在其基礎上,增添 多Item佈局 的內容並且整合到通用適配器及 ViewHolder 類中。
- 更改 data 類型 List -> ArrayList
- 將 MyAdapter2.java 傳入的數據類型由 Bean 改爲 Object,實現可複用
private ArrayList<Object> data = new ArrayList<Object>();
public MyAdapter2(Context context, ArrayList<Object> data) {
super(context,data);
}
- 去除 layoutId 變量
即 實現靈活佈局 部分不實現
public CommonAdapter(Context context, ArrayList<T> data)
{
this.mContext = context;
this.mData = data;
//this.mLayoutId = layoutId;
mInflater = LayoutInflater.from(context);
}
public MyAdapter2(Context context, ArrayList<Bean> data) {
super(context,data);
}
- 將 getView 作爲抽象函數,在 MyAdapter2.java 中實現它
爲此我們必須刪除函數convert()
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
//抽象方法
//public abstract void convert(ViewHolder holder,T data);
MyAdapter.java- 增加 Book.java 及其佈局文件 item2.xml
package com.example.reusable_baseadapter;
public class Book {
private String book_name;
public Book(String book_name){
this.book_name = book_name;
}
public String getName(){
return book_name;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/id_listview_item2_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
- 在 MyAdapter2.java 中重寫 getViewTypeCount 和 getItemViewType
//多佈局核心實現
@Override
public int getItemViewType(int position) {
if(mData.get(position) instanceof Book)
return type_Book;
else if(mData.get(position) instanceof Bean)
return type_Bean;
else
return super.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
return item_Type_Count;
}
- 在string.xml中添加如下代碼
<item name="Tag_Bean" type="id"/>
<item name="Tag_Book" type="id"/>
- 重寫 getView,實現 Item 多佈局
- 參考網上教程寫的,代碼非常臃腫,想到我們 ViewHolder 還沒用到,忍不住想優化一下,優化結果在後文
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
//獲取item視圖類型
int type = getItemViewType(position);
if (convertView == null)
{
//根據視圖類型加載
switch (type)
{
case type_Bean:
convertView = mInflater.inflate(R.layout.activity_listview_item1,parent,false);
holder1 = new ViewHolder1();
holder1.textView = (TextView) convertView.findViewById(R.id.id_listview_item1_text);
holder1.imageView = (ImageView) convertView.findViewById(R.id.id_listview_item1_image);
convertView.setTag(R.id.Tag_Bean,holder1);
break;
case type_Book:
convertView = mInflater.inflate(R.layout.activity_listview_item2,parent,false);
holder2 = new ViewHolder2();
holder2.textView = (TextView) convertView.findViewById(R.id.id_listview_item2_text);
convertView.setTag(R.id.Tag_Book,holder2);
break;
}
}
else
{
switch (type)
{
case type_Bean:
holder1 = (ViewHolder1)convertView.getTag(R.id.Tag_Bean);
break;
case type_Book:
holder2 = (ViewHolder2)convertView.getTag(R.id.Tag_Book);
break;
}
}
//設置控件的值
switch (type)
{
case type_Bean:
Bean bean = (Bean) mData.get(position);
holder1.textView.setText(bean.getName());
holder1.imageView.setBackgroundResource(bean.getImageId());
break;
case type_Book:
Book book = (Book)mData.get(position);
holder2.textView.setText(book.getName());
break;
}
return convertView;
}
private class ViewHolder1{
ImageView imageView;
TextView textView;
}
private class ViewHolder2{
TextView textView;
}
- 修改 MainActivity.java 中的 InitData,爲 ListView 添加不同類型的 Item
//修改數據初始化,加入Book類型數據
private void initData(){
for (int i = 1; i <= 10 ; i++){
Bean bean = new Bean("小豆豆"+i,R.drawable.bean_image);
Book book = new Book("Android測試指南");
data.add(bean);
data.add(book);
}
}
- 利用 ViewHolder.java 優化 getView 函數
//簡化getView()
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
//ViewHolder1 holder1 = null;
//ViewHolder2 holder2 = null;
//獲取item視圖類型
int type = getItemViewType(position);
ViewHolder holder_one = ViewHolder.get(mContext,convertView,parent,R.layout.activity_listview_item1,position);
ViewHolder holder_two = ViewHolder.get(mContext,convertView,parent,R.layout.activity_listview_item2,position);
if(type == type_Bean)
{
Bean bean = (Bean) mData.get(position);
TextView tv = (TextView) holder_one.getView(R.id.id_listview_item1_text);
tv.setText(bean.getName());
ImageView image = (ImageView) holder_one.getView(R.id.id_listview_item1_image);
image.setBackgroundResource(bean.getImageId());
return holder_one.getConvertView();
}
else if (type == type_Book)
{
Book book = (Book) mData.get(position);
TextView book_tv = (TextView) holder_two.getView(R.id.id_listview_item2_text);
book_tv.setText(book.getName());
return holder_two.getConvertView();
}
else
return convertView;
}
效果圖
ps:由於是寫完以後再整理的,這裏僅展示思路和部分代碼 完整代碼見 資源信息
如有疏漏及理解不到位的地方,還望大佬看到了能指點一二