Android中适用于ListView、GridView等组件的通用Adapter
? ? 今天隨便逛逛CSDN,看到主頁上推薦了一篇文章Android 高速開發系列 打造萬能的ListView GridView 適配器,剛好這兩天寫項目自己也封裝了相似的CommonAdapter,曾經也在github上看到過這種庫,于是自己也把自己的代碼再次整理出來與大家分享,也希望可以在CSDN這個平臺上學到很多其它的東西,以下就一起來看看吧。
? ? 平時我們在項目中使用到ListView和GridView組件都是都會用到Adapter,比較多的情況是繼承自BaseAdapter,然后實現getCount、getView等方法,再使用ViewHolder來提高一下效率.我們看以下一個簡單的樣例 :
ListView布局文件
fragment_main.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.example.push_demo_1.MainActivity$PlaceholderFragment" ><ListViewandroid:id="@+id/my_listview"android:layout_width="match_parent"android:layout_height="match_parent" /></RelativeLayout>ListView子項的布局文件
listview_item_layout.xml :
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal" ><ImageViewandroid:id="@+id/my_imageview"android:layout_width="64dp"android:layout_height="64dp"android:contentDescription="@string/app_name" /><TextViewandroid:id="@+id/my_textview"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:textSize="18sp" /></LinearLayout>曾經我們要寫下的Adapter代碼
public class NormalAdapter extends BaseAdapter {Context mContext;LayoutInflater mInflater;List<ListViewItem> mDataList;/*** @param context* @param data*/public NormalAdapter(Context context, List<ListViewItem> data) {mContext = context;mInflater = LayoutInflater.from(context);mDataList = data;}@Overridepublic int getCount() {return mDataList.size();}@Overridepublic ListViewItem getItem(int position) {return mDataList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder = null;if (convertView == null) {convertView = mInflater.inflate(R.layout.listview_item_layout, null, false);viewHolder = new ViewHolder();viewHolder.mImageView = (ImageView) convertView.findViewById(R.id.my_imageview);viewHolder.mTextView = (TextView) convertView.findViewById(R.id.my_textview);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.mImageView.setImageResource(getItem(position).mDrawableId);viewHolder.mTextView.setText(getItem(position).mText);return convertView;}/*** ViewHolder* * @author mrsimple*/static class ViewHolder {ImageView mImageView;TextView mTextView;}}? ? 然而寫過多遍以后我們發現我們總是反復地在寫這些getCount、getItem、getView方法以及ViewHolder,導致了非常多反復工作,而且及其無聊,于是我把這些反復工作抽象起來(曾經也有在github上看到這種通用Adapter實現),整理一下也便于自己使用,也是自己學習的一個過程。以下我們看看使用CommonAdapter后我們做與上面相同的工作須要怎么寫。
使用CommonAdapter后要寫的代碼
CommonAdapter<ListViewItem> listAdapter = new CommonAdapter<ListViewItem>(getActivity(),R.layout.listview_item_layout, mockListViewItems()) {@Overrideprotected void fillItemData(CommonViewHolder viewHolder, ListViewItem item) {// 設置圖片viewHolder.setImageForView(R.id.my_imageview, item.mDrawableId);// 設置textviewHolder.setTextForTextView(R.id.my_textview, item.mText);}}當中mockListViewImtes是準備了一些數據, 代碼例如以下 :? /*** 模擬一些數據* * @return*/private List<ListViewItem> mockListViewItems() {List<ListViewItem> dataItems = new ArrayList<ListViewItem>();dataItems.add(new ListViewItem(R.drawable.girl_96, "girl_96.png"));dataItems.add(new ListViewItem(R.drawable.fire_96, "fire_96.png"));dataItems.add(new ListViewItem(R.drawable.grimace_96, "grimace_96.png"));dataItems.add(new ListViewItem(R.drawable.laugh_96, "laugh_96.png"));return dataItems;}
可以看到,我們的代碼量降低了非常多,假設一個項目中有好幾個ListView、GridView等組件,我們就不須要反復做那么多無聊的工作了。我們看看效果圖 :?
CommonAdapter實現
/**** created by Mr.Simple, Aug 28, 201412:26:52 PM.* Copyright (c) 2014, hehonghui@umeng.com All Rights Reserved.** #####################################################* # #* # _oo0oo_ # * # o8888888o #* # 88" . "88 #* # (| -_- |) #* # 0\ = /0 # * # ___/`---'\___ #* # .' \\| |# '. #* # / \\||| : |||# \ #* # / _||||| -:- |||||- \ #* # | | \\\ - #/ | | #* # | \_| ''\---/'' |_/ | #* # \ .-\__ '-' ___/-. / #* # ___'. .' /--.--\ `. .'___ #* # ."" '< `.___\_<|>_/___.' >' "". #* # | | : `- \`.;`\ _ /`;.`/ - ` : | | #* # \ \ `_. \_ __\ /__ _/ .-` / / #* # =====`-.____`.___ \_____/___.-`___.-'===== #* # `=---=' #* # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #* # #* # 佛祖保佑 永無BUG #* # #* #####################################################*/package com.uit.commons;import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter;import java.util.List;/*** 這是一個通用、抽象的適配器類,覆寫了BaseAdapter的getCount, getItem, getItemId,* getView方法,在getView方法中通過* 通用的CommonViewHolder來對convertView的進行處理,而且緩存convertView中的其它View元素* ,降低了ListView、GridView 等組件的Adapter和ViewHolder的代碼量.* 用戶僅僅須要在fillItemData函數中將第position位置里的數據填充到listview或者gridview的第position的view中就可以* ,詳細使用實例參考文檔.* * @author mrsimple* @param <T> 數據源的類型*/ public abstract class CommonAdapter<T> extends BaseAdapter {/*** Context*/Context mContext;/*** 要展示的數據列表*/List<T> mData;/*** 每一項的布局id,比如R.layout.my_listview_item.*/private int mItemLayoutId = -1;/*** @param context Context* @param itemLayoutResId* 每一項(適用于listview、gridview等AbsListView子類)的布局資源id,比如R.layout.* my_listview_item.* @param dataSource 數據源*/public CommonAdapter(Context context, int itemLayoutResId, List<T> dataSource) {checkParams(context, itemLayoutResId, dataSource);mContext = context;mItemLayoutId = itemLayoutResId;mData = dataSource;}/*** 檢查參數的有效性* * @param context* @param itemLayoutResId* @param dataSource*/private void checkParams(Context context, int itemLayoutResId, List<T> dataSource) {if (context == null || itemLayoutResId < 0 || dataSource == null) {throw new RuntimeException("context == null || itemLayoutResId < 0 || dataSource == null, please check your params");}}/*** 返回數據的總數*/@Overridepublic int getCount() {return mData.size();}/*** 返回position位置的數據*/@Overridepublic T getItem(int position) {return mData.get(position);}/*** item id, 返回position*/@Overridepublic long getItemId(int position) {return position;}/*** 返回position位置的view, 即listview、gridview的第postion個view*/@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 獲取ViewHolderCommonViewHolder viewHolder = CommonViewHolder.getViewHolder(mContext, convertView,mItemLayoutId);// 填充數據fillItemData(viewHolder, getItem(position));// 返回convertviewreturn viewHolder.getConvertView();}/*** 用戶必須覆寫該方法來講數據填充到視圖中* * @param viewHolder 通用的ViewHolder, 里面會裝載listview,* gridview等組件的每一項的視圖,而且緩存其子view* @param item 數據源的第position項數據*/protected abstract void fillItemData(CommonViewHolder viewHolder, T item);}CommonViewHolder實現
/**** created by Mr.Simple, Aug 28, 201412:32:45 PM.* Copyright (c) 2014, hehonghui@umeng.com All Rights Reserved.** #####################################################* # #* # _oo0oo_ # * # o8888888o #* # 88" . "88 #* # (| -_- |) #* # 0\ = /0 # * # ___/`---'\___ #* # .' \\| |# '. #* # / \\||| : |||# \ #* # / _||||| -:- |||||- \ #* # | | \\\ - #/ | | #* # | \_| ''\---/'' |_/ | #* # \ .-\__ '-' ___/-. / #* # ___'. .' /--.--\ `. .'___ #* # ."" '< `.___\_<|>_/___.' >' "". #* # | | : `- \`.;`\ _ /`;.`/ - ` : | | #* # \ \ `_. \_ __\ /__ _/ .-` / / #* # =====`-.____`.___ \_____/___.-`___.-'===== #* # `=---=' #* # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #* # #* # 佛祖保佑 永無BUG #* # #* #####################################################*/package com.uit.commons;import android.content.Context; import android.graphics.Bitmap; import android.view.View; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView;import com.uit.commons.utils.ViewFinder;/*** 這是一個通用的ViewHolder, 將會裝載AbsListView子類的item View, 而且將item* view中的子視圖進行緩存和索引,使得用戶可以方便的獲取這些子view, 降低了代碼反復。* * @author mrsimple*/ public class CommonViewHolder {/*** 構造函數* * @param context Context* @param layoutId ListView、GridView或者其它AbsListVew子類的 Item View的資源布局id*/protected CommonViewHolder(Context context, int layoutId) {// 初始化布局, 裝載ContentViewViewFinder.initContentView(context, layoutId);// 將ViewHolder存儲在ContentView的tag中ViewFinder.getContentView().setTag(this);}/*** 獲取CommonViewHolder,當convertView為空的時候從布局xml裝載item view,* 而且將該CommonViewHolder設置為convertView的tag, 便于復用convertView.* * @param context Context* @param convertView Item view* @param layoutId 布局資源id, 比如R.layout.my_listview_item.* @return 通用的CommonViewHolder實例*/public static CommonViewHolder getViewHolder(Context context, View convertView, int layoutId) {if (convertView == null) {return new CommonViewHolder(context, layoutId);}return (CommonViewHolder) convertView.getTag();}/*** @return 當前項的convertView, 在構造函數中裝載*/public View getConvertView() {return ViewFinder.getContentView();}/*** 為id為textViewId的TextView設置文本內容* * @param textViewId 視圖id* @param text 要設置的文本內容*/public void setTextForTextView(int textViewId, CharSequence text) {TextView textView = ViewFinder.findViewById(textViewId);if (textView != null) {textView.setText(text);}}/*** 為ImageView設置圖片* * @param imageViewId ImageView的id, 比如R.id.my_imageview* @param drawableId Drawable圖片的id, 比如R.drawable.my_photo*/public void setImageForView(int imageViewId, int drawableId) {ImageView imageView = ViewFinder.findViewById(imageViewId);if (imageView != null) {imageView.setImageResource(drawableId);}}/*** 為ImageView設置圖片* * @param imageViewId ImageView的id, 比如R.id.my_imageview* @param bmp Bitmap圖片*/public void setImageForView(int imageViewId, Bitmap bmp) {ImageView imageView = ViewFinder.findViewById(imageViewId);if (imageView != null) {imageView.setImageBitmap(bmp);}}/*** 為CheckBox設置是否選中* * @param checkViewId CheckBox的id* @param isCheck 是否選中*/public void setCheckForCheckBox(int checkViewId, boolean isCheck) {CheckBox checkBox = ViewFinder.findViewById(checkViewId);if (checkBox != null) {checkBox.setChecked(isCheck);}} }ViewFinder輔助類
/*** view finder, 方便查找View。用戶須要在使用時調用initContentView,* 將Context和布局id傳進來,然后使用findViewById來獲取須要的view* ,findViewById為泛型方法,返回的view則直接是你接收的類型,而不須要進行強制類型轉換.比方,* 曾經我們在Activity中找一個TextView通常是這樣 : * TextView textView = (TextView)findViewById(viewId); * 假設頁面中的控件比較多,就會有非常多的類型轉換,而使用ViewFinder則免去了類型轉換,* 示比例如以下 : * TextView textView = ViewFinder.findViewById(viewId);* * @author mrsimple*/ public final class ViewFinder {/*** LayoutInflater*/static LayoutInflater mInflater;/*** 每項的View的sub view Map*/private static SparseArray<View> mViewMap = new SparseArray<View>();/*** Content View*/static View mContentView;/*** 初始化ViewFinder, 實際上是獲取到該頁面的ContentView.* * @param context* @param layoutId*/public static void initContentView(Context context, int layoutId) {mInflater = LayoutInflater.from(context);mContentView = mInflater.inflate(layoutId, null, false);if (mInflater == null || mContentView == null) {throw new RuntimeException("ViewFinder init failed, mInflater == null || mContentView == null.");}}/*** @return*/public static View getContentView() {return mContentView;}/*** @param viewId* @return*/@SuppressWarnings("unchecked")public static <T extends View> T findViewById(int viewId) {// 先從view map中查找,假設有的緩存的話直接使用,否則再從mContentView中找View tagetView = mViewMap.get(viewId);if (tagetView == null) {tagetView = mContentView.findViewById(viewId);mViewMap.put(viewId, tagetView);}return tagetView == null ? null : (T) mContentView.findViewById(viewId);} }? ? ? ? ?代碼都在Github上了,請猛擊這里。
總結
以上是生活随笔為你收集整理的Android中适用于ListView、GridView等组件的通用Adapter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA 设计模式 观察者模式
- 下一篇: asterisk channel dri