編輯:關於Android編程
大多App都會使用到的基本控件 ——- Listiew,特別像新聞浏覽類的比如說“今日關注”,或者“應用寶”這種匯集手機軟件集合的。而且大家都知道 需要給每個單獨的 ListView 搭配相應的適配器 Adapter 。如果你的項目中使用ListView 的頻率很少甚至沒有,那我不建議你對 ListView 進行抽取封裝,但是!如果它的使用滲透到App中大多頁面時,你必須考慮 對Adapter的公共方法進行抽取封裝到單獨的類中,來避免整個項目代碼的冗雜,使代碼結構規范化!
HomeFragment.java @Override public View onCreateSuccessView() { ListView view = new ListView(UIUtils.getContext()); initData(); view.setAdapter(new HomeAdapter()); return view; } private void initData() { for (int i = 0; i < 50; i++) { mList.add("測試數據" + i); } } class HomeAdapter extends BaseAdapter { @Override public int getCount() { return mList.size(); } @Override public String getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { convertView = View.inflate(UIUtils.getContext(), R.layout.list_item_home, null); holder = new ViewHolder(); holder.tvContent = (TextView) convertView .findViewById(R.id.tv_content); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tvContent.setText(getItem(position)); return convertView; } } static class ViewHolder { public TextView tvContent; }
這裡我們主要 把重點放在 Adapter 和 ViewHolder 的抽取封裝,首先簡單分析其邏輯組成:
1.首先看到我自定義的 HomeAdapter 繼承的是 BaseAdapter 。繼承的四個方法中,前三個:getCount 、getItem 、getItemId 看的出來方法及其簡單,只涉及到一個不確定量——顯示的數據類,易封裝,使用泛型定義數據類型即可。
但是getView方法中步驟略復雜,首先梳理清楚方法裡的邏輯,才好進一步的封裝:
(1)加載布局文件,布局轉換(xml —> view)
(2)初始化控件(finViewById)
(3)給ViewHolder設置標記(setTag),便於下次復用
(4)給控件設置數據
static class ViewHolder { public TextView tvContent; }
2. ViewHolder 類中定義的是一個單獨條目中的所有控件聲明,也許你會發現 不同的ListView中適配器 Adapter中有共性的方法,但是 不同頁面中展示條目不盡相同,根本無法提取。事實的確是這樣,但是Adapter中肯定會用到 ViewHolder類 ,而且getView方法中的部分邏輯還要依靠這個類去完成,所以我們還是 要繼續提取一個基類 BaseHolder,至於取決於不同頁面邏輯也不同的地方,封裝一個抽象方法丟給子類去實現即可!
1.抽取BaseAdapter的共性方法,封裝到MyBaseAdapter類
/** * 數據適配器的基類 * 展示的數據類型不確定,故使用泛型! */ public class MyBaseAdapterextends BaseAdapter { private ArrayList list; public MyBaseAdapter(ArrayList list) { this.list = list; } @Override public int getCount() { return list.size(); } @Override public T getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { return null; } }
首先我們對 繼承Basedapter的三個方法:getCount 、getItem 、getItemId 進行封裝,由於方法中涉及到 展示的條目數據,這裡要增加一個 構造方法 —— 用來接收 數據集合。至於展示的數據集合類型無法確定,所以才用泛型來定義數據集。定義的類也要加上泛型。MyBaseAdapter
2. getView 封裝
這裡只剩下getView方法還未封裝,我們再次復習其中邏輯:
(1)加載布局文件,布局轉換(xml —> view)
(2)初始化控件(finViewById)
(3)給ViewHolder設置標記(setTag),便於下次復用
(4)給控件設置數據
MyBaseAdapter.java
@Override
public View getView(int position, View convertView, ViewGroup parent) {
BaseHolder holder = null;
if (convertView == null) {
// 在初始化holder的同時,已經對布局進行了加載,也給view設置了tag
holder = getHolder(position);
} else {
holder = (BaseHolder) convertView.getTag();
}
// 刷新界面,更新數據
holder.setData(getItem(position));
return holder.getRootView();
}
// 返回BaseHolder的子類,必須實現
public abstract BaseHolder getHolder(int position);
首先初始化我們從ViewHolder中提取的基類泛型
BaseHolder
(1)前3點邏輯 主要依賴於具體的頁面,不同的頁面應當對應不同的ViewHolder,所以在這個封裝一個抽象方法getHolder ,交由 子類繼承 MyBaseAdapter去實現!
(2)第四點邏輯 ,更新數據,直接調用 BaseHolder中的方法。
三. BaseHolder封裝
1.抽取ViewHolder的功能,封裝到BaseHolder類
由以上可知,BaseHolder類中應做的事
1. 初始化item布局,2. findViewById方法:一個抽象方法,由子類在初始化布局時實現!
3. 給view設置tag:在BaseHolder的構造方法中實現!
4. 刷新界面:抽象方法,由子類去實現!
所以,BaseHolder相當於是對getView方法的封裝!
public abstract class BaseHolder {
private View mRootView;// item的布局對象
private T data;// item對應的數據
public BaseHolder() {
mRootView = initView();// 初始化布局
mRootView.setTag(this);// 給view設置tag
}
// 初始化布局的方法必須由子類實現
public abstract View initView();
// 返回布局對象
public View getRootView() {
return mRootView;
};
// 設置數據
public void setData(T data) {
this.data = data;
refreshView(data);
}
// 獲取數據
public T getData() {
return data;
}
// 刷新界面,更新數據,子類必須實現
public abstract void refreshView(T data);
}
——–以上已經封裝完畢!———–
四. BaseHolder耦合於getView
解析BaseHolder:
若按照以上解釋,那BaseHolder只需要兩個抽象方法和構造函數即可,可並非如此!既然BaseHolder是對getView方法的一個封裝,那它需要完成getView中的所有功能,可它跟getView方法是耦合的,所以需要相互配合,再查看封裝好的 getView方法:
MyBaseAdapter.java
@Override
public View getView(int position, View convertView, ViewGroup parent) {
BaseHolder holder = null;
if (convertView == null) {
// 在初始化holder的同時,已經對布局進行了加載,也給view設置了tag
holder = getHolder(position);
} else {
holder = (BaseHolder) convertView.getTag();
}
// 刷新界面,更新數據
holder.setData(getItem(position));
return holder.getRootView();
}
// 返回BaseHolder的子類,必須實現
public abstract BaseHolder getHolder(int position);
1. 這裡的holder調用的是 由子類實現的抽象方法,
// 在初始化holder的同時,已經對布局進行了加載,也給view設置了tag
holder = getHolder(position);
具體就是new 一個 繼承BaseHolder 的子類,所以我們new完這個子類後,需要完成getView的1.2.3點邏輯。所以在 Baseholder中的構造方法中完成此3點邏輯(抽象方法)。
// 刷新界面,更新數據
holder.setData(getItem(position));
2. 而這裡的設置數據的方法不適合直接設為抽象,因為涉及到數據的傳遞(數據類型不確定,依舊為泛型)。方法中第一步是接收數據,第二步才是刷新數據。我們的做法是把第二步的邏輯(刷新數據)單獨拿出來,封裝成一個抽象方法,留給子類BaseHolder去實現!
return holder.getRootView();
3.getView 的最後一步 —— 將當前item的View返回!可是我們具體View的初始化都交由子類實現了,BaseHodler 並無View。這時我們就要在BaseHodler 單獨定義一個方法getRootView()來返回當前item的布局。
以上,才是BaseAdapter 和ViewHolder的完美搭配,即MyBaseAdapter 和 BaseHodler 完美搭配
舉一個栗子:
MyBaseAdapter 的繼承:
HomeFragment.java
public class HomeFragment extends BaseFragment {
private ArrayList data;
@Override
public View onCreateSuccessView() {
initData();
ListView view = new ListView(UIUtils.getContext());
view.setAdapter(new HomeAdapter(data));
return view;
}
private void initData(){
for (int i = 0; i < 50; i++) {
data.add("測試數據" + i);
}
class HomeAdapter extends MyBaseAdapter {
private ArrayList data;
public HomeAdapter(ArrayList data) {
super(data);
}
@Override
public BaseHolder getHolder() {
return new HomeHolder();
}
}
BaseHodler 的繼承:
public class HomeHolder extends BaseHolder {
private TextView tvContent;
@Override
public View initView() {
// 1. 加載布局
View view = UIUtils.inflate(R.layout.list_item_home);
// 2. 初始化控件
tvContent = (TextView) view.findViewById(R.id.tv_content);
return view;
}
@Override
public void refreshView(Stringdata) {
tvContent.setText(data);
}
}
喔~~~~大家感覺到了嗎?!代碼量驟減啊!!!好處自是不必多說,用心體會~
希望對你有幫助 :)
android中圖像在畫布上放大縮小時,圖像的邊框大小沒有改變!原圖如下:放大後:原來圖片的邊框沒有改變,位置依舊!所以如果要放置圖片的位置的話,就需要做相應的位置移動才
先上效果圖1.activity_main.xml<?xml version=1.0 encoding=utf-8?><RelativeL
1、DataProvider package com.njupt.ndk_passdata; public class DataProvider { public
一、第一種方法: (1)Fragment的第一種使用方法是使用fragment加載單獨的布局文件:(也就是xml的方式實現) 結構如下: activity_main.