作者: 夏至 歡迎轉載,也請保留這段申明
http://blog.csdn.net/u011418943/article/details/73555178
最近在開發一個新項目,由于是給平板用的,且公司平臺用 recyclerview 比較麻煩,索性就用listview,畢竟也不用太多復雜布局;但由于用到比較多的listview,那么要每個多寫嗎?當然不用,我們可以寫一個基類,然后繼承即可。
參考鴻洋大神的文章 :http://blog.csdn.net/lmj623565791/article/details/38902805/
先看效果圖:
再附上張圖片:
上述的listview 只要幾行代碼就可以了:
mAdapter = new CommonAdapter<RunAppInfo>(SpeedUpActivity.this, datas, R.layout.listview_item) {
@Override
public void convert(ViewHolder viewHolder, RunAppInfo data) {
viewHolder.setText(R.id.app_name,data.getName());
viewHolder.setText(R.id.app_size,data.getMemery());
viewHolder.setDrawable(R.id.app_icon,data.getIcon());
}
};
mListView.setAdapter(mAdapter);
1、 常用listview的 baseadapter寫法
public class AppContentAdapter extends BaseAdapter{
private Context mContext;
private List<AppContent> mList;
@SuppressWarnings("deprecation")
public AppContentAdapter(Context context,List<AppContent> list){
mContext = context;
mList = list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mList.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return mList.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
class ViewHolder{
TextView appname;
}
@Override
public View getView(int arg0, View contentView, ViewGroup arg2) {
ViewHolder viewHolder = null;
if (contentView == null) {
contentView = LayoutInflater.from(mContext).inflate(R.layout.appcontent, null);
viewHolder = new ViewHolder();
viewHolder.appname = (TextView) contentView.findViewById(R.id.app_name);
contentView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) contentView.getTag();
}
viewHolder.appname.setText(mList.get(arg0).getName());
return contentView;
}
}
相信你已經對它很熟悉了,但是加入,我們一個項目要用到很多的 listview 我們其實是在做重復功,那我們能不能把這個listview 給封裝起來呢?
2、通用的viewholder
當然可以,首先,我們先從getview來封裝,注意到這是個 viewholder,那我們就先封裝個 viewholder好了。首先,我們通過 setTag 和 getTag 這種方式來獲取 view 的。那么實體類首先如下所示,getViewHolder 表示viewholder的實例:
public class ViewHolder {
/**
* 可以理解成單例吧,獲取一個viewholder
* @param context
* @param converView
* @param layout
* @param parent
* @param position
* @return
*/
public static ViewHolder getViewHolder(Context context, View converView, int layout,
ViewGroup parent,int position){
if (converView ==null){ //當為空時,我們需要實例化viewholder
//注意這里,其實跟baseadapter的判斷是一致的,其中settag也是在viewholder里
ViewHolder viewholder = new ...
return viewholder;
}else{
ViewHolder holder = (ViewHolder) converView.getTag();
return holder;
}
}
}
在 getViewHolder 中,就是用來獲取 viewholder 的,當然這里我們并未寫實例化,只寫了 getTag 而傳遞的參數我們也是比較熟悉,接著完善一下,提供一下setTag,代碼如下:
public class ViewHolder {
private Context mContext;
private View mConverView;
private static int mPosition;
public ViewHolder(Context context, int layout, ViewGroup parent,int position){
mContext = context;
mConverView = LayoutInflater.from(mContext).inflate(layout,parent,false);
mConverView.setTag(this);
mPosition = position; //防止滑動導致item的position錯誤
}
/**
* 可以理解成單例吧,獲取一個viewholder
* @param context
* @param converView
* @param layout
* @param parent
* @param position
* @return
*/
public static ViewHolder getViewHolder(Context context, View converView, int layout,
ViewGroup parent,int position){
if (converView ==null){
//注意這里,其實跟baseadapter的判斷是一致的,其中settag也是在viewholder里
return new ViewHolder(context,layout,parent,position);
}else{
ViewHolder holder = (ViewHolder) converView.getTag();
mPosition = position;
return holder;
}
}
/**
* 返回一個viewholder
* @return
*/
public View getConverView() {
return mConverView;
}
}
可以看到,當我們在用的時候,其實用 getViewHolder 這種類似單例的方式的,而在實例中,加載 layout;ok,既然 viewholder 的setTag 和getTag 已經寫好,接著就是通過 viewholder 來獲取 view 了,那么就是一個 id 對應一個 view 了,我們可以用 sparsearray 來達到我們的效果,由于我們不知道TextView 、ImageView 等等,所以這里用泛型來寫,順便,我們也把一些常用方法寫上,改良之后的代碼如下:
public class ViewHolder {
private Context mContext;
private View mConverView;
private static int mPosition;
private SparseArray<View> mViewSparseArray;
public ViewHolder(Context context, int layout, ViewGroup parent,int position){
mContext = context;
mConverView = LayoutInflater.from(mContext).inflate(layout,parent,false);
mViewSparseArray = new SparseArray<>();
mConverView.setTag(this);
mPosition = position;
}
/**
* 可以理解成單例吧,獲取一個viewholder
* @param context
* @param converView
* @param layout
* @param parent
* @param position
* @return
*/
public static ViewHolder getViewHolder(Context context, View converView, int layout,
ViewGroup parent,int position){
if (converView ==null){
//注意這里,其實跟baseadapter的判斷是一致的,其中settag也是在viewholder里
return new ViewHolder(context,layout,parent,position);
}else{
ViewHolder holder = (ViewHolder) converView.getTag();
mPosition = position;
return holder;
}
}
/**
* 返回一個viewholder
* @return
*/
public View getConverView() {
return mConverView;
}
/**
* key-value 通過sparseArray來獲取view,屬性不同,這里用一個泛型來實現
* @param viewid
* @param <T>
* @return
*/
public <T extends View> T getView(int viewid){
View view = mViewSparseArray.get(viewid);
if (view == null){
view = mConverView.findViewById(viewid);
mViewSparseArray.put(viewid,view);
}
return (T) view;
}
/**
* 設置text
* @param viewid
* @param msg
*/
public void setText(int viewid,String msg){
TextView tv = (TextView) mConverView.findViewById(viewid);
tv.setVisibility(View.VISIBLE);
tv.setText(msg);
}
/**
* 設置drawable
* @param viewid
* @param drawable
*/
public void setDrawable(int viewid, Drawable drawable){
ImageView iv = (ImageView) mConverView.findViewById(viewid);
iv.setImageDrawable(drawable);
}
/**
* 設置checkbox
* @param viewid
* @param status
*/
public void setCheckbox(int viewid,boolean status){
CheckBox cb = (CheckBox) mConverView.findViewById(viewid);
cb.setVisibility(View.VISIBLE);
cb.setChecked(status);
}
/**
* 設置itemview 的背景
* @param viewid
* @param status
*/
public void setItemBackground(int viewid,int resourid){
View view = mConverView.findViewById(viewid);
//Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),resourid);
view.setBackgroundResource(resourid);
}
}
這樣,我們的一個通用viewholder就可以了。但我們的工作還沒有完成,viewholder封裝好了,但是 adapter呢?所以,我們封裝后的adapter 如下:
public abstract class CommonAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List<T> mDatas;
private int mLayoutId;
public CommonAdapter(Context context, List<T> datas,int layoutid) {
mContext = context;
mDatas = datas;
mLayoutId = layoutid;
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public T getItem(int i) {
return mDatas.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
public abstract void convert(ViewHolder viewHolder,T data);
/**
* 這里把布局什么的,都在getview中,設置好,其中viewholder是我們的通用的adapter
* 然后把需要實現的邏輯用抽象方法公布出去,自己去實現
* @param i
* @param view
* @param viewGroup
* @return
*/
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder = ViewHolder.getViewHolder(mContext,view,mLayoutId,viewGroup,i);
convert(viewHolder,getItem(i));
return viewHolder.getConverView();
};
}
可以看到,我們的 listview 基本都是用一個實體類來實現的,所以在初始化的時候,用一個泛型來表示,接著,我們在 getView 中,初始化上面封裝好的 ViewHolder,把要實例化itemview 的方法公布出來,讓用戶自己去定制。這樣,在是用的就可以這樣用了:
//采用通用listview封裝adapter
mAdapter = new CommonAdapter<RunAppInfo>(SpeedUpActivity.this, datas, R.layout.listview_item) {
@Override
public void convert(ViewHolder viewHolder, RunAppInfo data) {
viewHolder.setText(R.id.app_name,data.getName());
viewHolder.setText(R.id.app_size,data.getMemery());
viewHolder.setDrawable(R.id.app_icon,data.getIcon());
}
};
mListView.setAdapter(mAdapter);
封裝好的代碼,是不是比以前整潔好看多了;當然,這里我們只用了一次,并不能體現它的好處,加入我還要用多一個 listview 呢?就不用再去寫多一個 listview ,直接這樣使用即可:
CommonAdapter<StorageInfo> adapter = new CommonAdapter<StorageInfo>(DeepClearActivity.this,
mScanDatas,R.layout.listview_detail_item) {
@Override
public void convert(ViewHolder viewHolder, StorageInfo data) {
viewHolder.setDrawable(R.id.list_icon,data.getIcon());
viewHolder.setText(R.id.list_name,data.getName());
viewHolder.setText(R.id.list_path,data.getPath());
viewHolder.setText(R.id.list_size,Formatter.formatFileSize(DeepClearActivity.this,data.getSize()));
int status = data.getStatus();
String statustext = null;
if (status != ToolUtils.UNINSTALLED){
statustext = getString(R.string.installed);
}else{
statustext = getString(R.string.clickinstall);
}
viewHolder.setText(R.id.list_status,statustext);
}
};
mDeepDetailListview.setAdapter(adapter);
3、listview 動畫
上面的效果圖中,我們是有效果圖的,那么怎么做呢? listview 是一個 viewground,所以,它也支持 setLayoutAnimation ,所以,我們的動畫可以這樣寫
listview 進入 :
//設置listview 進入動畫
Animation translate = new TranslateAnimation(800,0,0,0);
translate.setDuration(300);
translate.setInterpolator(new DecelerateInterpolator());
LayoutAnimationController lac = new LayoutAnimationController(translate);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
mDeepDetailListview.setLayoutAnimation(lac);
mDeepDetailListview.startLayoutAnimation();
退出動畫
//設置listview 退出動畫
Animation translate = new TranslateAnimation(0,800,0,0);
translate.setDuration(300);
translate.setInterpolator(new DecelerateInterpolator());
translate.setFillAfter(true);
LayoutAnimationController lac = new LayoutAnimationController(translate);
lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
mDeepDetailListview.setLayoutAnimation(lac);
mDeepDetailListview.startLayoutAnimation();
非常簡單,就是一個簡單的補件動畫