由於手機螢幕尺寸的原因以及手指觸屏操作的特性,ListView常常用到。在Android學習筆記(十一):Activity-ListView中,每一個list中的entry只有一個資料,且都只涉及一個view,在本次,我們將學習進一步的變化,讓list更為生動,這隻需對apdater作進一步的描述。
例子一:每個元素有一個表徵圖和一個資訊資料
1)設定主介面的XML檔案
<LinearLayout ...>
<!-- 我們需要對list的entry進行地功能之,所以id採用"@android:id/list" -->
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
2)設定每個元素格式entry.xml格式
<LinearLayout ...>
<!-- 在每一個元素中(每一行list中),有一個image icon,然後是我們的資料資訊 -->
<ImageView android:id="@+id/c82_icon"
android:layout_width="44px"
android:paddingLeft="2px"
android:paddingRight="2px"
android:paddingTop ="10px"
android:layout_height="wrap_content"
android:src="@drawable/android_normal" />
<TextView android:id="@+id/c82_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="44sp" />
</LinearLayout>
3)原始碼
原始碼很簡單,可以參考Android學習筆記(十一):Activity-ListView中的第一個例子。不同的是設定adapter的寫法,原來的例子採用了android提供UI格式android.R.layout.simple_list_item_1,在這個例子中我們將採用自訂的layout格式來描述list增個中的元素:
public class Chapter8Test2 extends ListActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chapter_8_test2);
/* 第一個參數是context,最後一個參數是資料資訊來源item,第二個參數是描述entry的layout xml檔案,第三個參數是資料資訊來源對應元素layout中的哪一個widget。*/
setListAdapter ( new ArrayAdapter<String>( this,R.layout.entry,R.id.c82_label,Chapter8.items));
}
public void onListItemClick(ListView parent, View view, int position, long id){
Toast.makeText(getApplicationContext(), Chapter8.items[position], Toast.LENGTH_SHORT).show();
}
例子二:根據layout xml檔案,動態設定每個元素
上面的方式可以處理簡單的方式,但是下面兩種情況
- 不是所有的單元都使用同一個layout
- 需要設定在list單元中的widget,例如使用不同的icon
我們需要建立adapter的子類,通過重寫getView()來描述自己的單元風格。在下面的例子中,我們對第一個例子進行修改,對於長短不同的單詞,使用不同的icon。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chapter_8_test2);
setListAdapter(new IconicAdapter());
}
private class IconicAdapter extends ArrayAdapter<String>{
/* 步驟1:編寫建構函式,對於第一個例子,我們填入格式layout xml檔案和資料來源,以便完成必要的初始化工作 */
IconicAdapter(){
super(Chapter8Test3.this,R.layout.entry,Chapter8.items);
}
/*步驟2:通過重寫getView(),具體描述每個元素的格式,輸入中position表示list的順序位置,我們返回的View即使list在position位置的元素的呈現 */
public View getView(int position, View convertView, ViewGroup parent) {
/* 步驟2.1:根據layout xml檔案,通過LayoutInflater影射到一個View對象,作為我們list元素UI的基礎 */
//LayoutInflater類是用於將layout XML檔案執行個體化為相應的view對象,它從不直接使用,而是使用getLayoutInflater()或者getSystemService(String)來獲得已掛在當前context標準的LayoutInflater執行個體。例如:LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater infalter = getLayoutInflater();
//從第一個參數獲得相關的XML的結構,第二個參數是ViewGroup root,最後一個參數表示如果有錯誤,是否扔出InflateException。
View row=infalter.inflate(R.layout.entry, parent,
false);
/* 步驟2.2:具體設定每個View中各個widget的格式和資訊 ,在這個例子中,如果資訊長度大於4顯示一種表徵圖,小於等於顯示另一種表徵圖*/
TextView label=(TextView)row.findViewById(R.id.c82_label);
ImageView icon = (ImageView)row.findViewById(R.id.c82_icon);
label.setText(Chapter8.items[position]);
if(Chapter8.items[position].length() > 4){
icon.setImageResource(R.drawable.android_focused);
}else{
icon.setImageResource(R.drawable.android_normal);
}
/*步驟2.3,返回對應position位置的view */
return row;
}
}
例子三:讓程式更有效率
例子二可以靈活設定每一個list元素的UI,但是在效率方面,每次滑動,都需要根據getView()來擷取view,這對於快速移動時,會出現獃滯緩慢的現象,同時每次CPU的計算也消耗手機電池。在getView()中,有一個參數為View convertView,當我們第一次給出這個元素的UI的View時,convertView為零,此後convertView為我們之前所建立的view對象(重複利用,也避免java在garbage收集時消耗CPU[消耗電源])。可以重複利用我們之前建立的View,如果需要對內容進行改變,可以通過findViewById獲得對應的widget對象,對內容進行設定,這樣UI只重新整理設定的部分。下面是例子三對例子二中getView的修改。
/*為了是程式更有效率,利用之前已經建立的View(即第二個參數),只有第一次顯示該元素時,方建立新的View*/
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
//在這個例子中,由於widget的內容不變, 可以在第一次設定中賦值。在本例子中我們按動態顯示(需要處理其中的變化),將內容每次都重新設定
if(row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.chapter_8_test2_entry,parent,false);
}
TextView label=(TextView)row.findViewById(R.id.c82_label);
label.setText(Chapter8.items[position]);
ImageView icon = (ImageView)row.findViewById(R.id.c82_icon);
label.setText(Chapter8.items[position]);
if(Chapter8.items[position].length() > 4){
icon.setImageResource(R.drawable.android_focused);
}else{
icon.setImageResource(R.drawable.android_normal);
}
return row;
}
例子四:讓程式進一步有效率 setTag( )
在上面的例子,我們重複利用了已建立的View,但是findViewById需要在View的層次中尋找,如果View的結構複雜,同樣也是消耗CPU的。此外對於每個List元素,在實際的程式中,list元素可能還會儲存某些資料。在這個例子,我們引入setTag()和getTag()兩個方法。每個View都可以通過setTag()綁帶一個object,可以通過getTag()將這個object取出來,這樣可以避免findViewById對widget的層層查詢,做到快速定位。
//步驟一:設定一個class用來儲存list元素的資訊
class ViewWrapper{
View base;
TextView label = null;
ImageView icon = null;
ViewWrapper(View base){
this.base = base;
}
TextView getLabel(){
if(label == null)
label = (TextView)base.findViewById(R.id.c82_label);
return label;
}
ImageView getIcon(){
if(icon == null)
icon = (ImageView)base.findViewById(R.id.c82_icon);
return icon;
}
}
... ...餘下內容同例子2和例子3,我們重寫IconicAdapter的getView()
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ViewWrapper wrapper = null;
//步驟2:如果沒有建立View,建立之,並通過setTag()捆綁ViewWrapper對象,如果已經建立,通過getTag()擷取ViewWrapper對象。
if(row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.chapter_8_test2_entry,parent,false);
wrapper = new ViewWrapper(row);
row.setTag(wrapper);
}else{
wrapper = (ViewWrapper) row.getTag();
}
wrapper.getLabel().setText(Chapter8.items[position]);
if(Chapter8.items[position].length() > 4){
wrapper.getIcon().setImageResource(R.drawable.android_focused);
}else{
wrapper.getIcon().setImageResource(R.drawable.android_normal);
}
return row;
}
}
相關連結:我的Andriod開發相關文章