使用定制的ArrayAdapter制作ListView的Items(翻譯)



Translated by:AcerWang    原文出自:customizing-android-listview-items-with-custom-arrayadapter  

背景介紹

  對於現實世界中的商業移動應用來說,Android的ListView默認的界面外觀不是非常有吸引力。它只是使用了內部的TextView控件,在每個ListView的行(Row)里面傳遞了一個簡單的字符串而已。大多數應用,你會想要創建出富含圖形界面和呈現給用戶視覺體驗良好的應用。幸運地是,ListView 是一個非常強大的控件,由於有可定制的item 布局的幫助,它可以被定制從而輕松地適應你的需求。在本文中,我將向你展示怎樣創建一個定制的ListView  Item(有圖標,自定義的header布局)以及怎樣使用定制的ArrayAdapter將他們聯系起來。我也會向你展示一些性能優化的小方法來優化你的ListView控件的內存占用。下面用一個例子來展示:

      圖1. 天氣圖                            圖2. 布局結構圖

 

            

   一、項目布局

  在Eclipse中,創建一個新的Android項目,使用默認的Activity和main.xml布局文件。在main.xml文件中,聲明一個ListView控件。

 main.xml文件:
1
<?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android=http://schemas.android.com/apk/res/android 4 android:orientation="vertical" 5 android:layout_width="fill_parent" 6 android:layout_height="fill_parent" 7 android:background="#FFFFFF"> 8 9 <ListView 10 android:id="@+id/listView1" 11 android:layout_width="fill_parent" 12 android:layout_height="fill_parent" /> 13 </LinearLayout>

  上面的代碼,使用了簡單的線性布局方式,內部垂直排列。聲明了一個ListView,占據整個父容器,他的android.layout_width和android.layout_width的屬性都為fill_parent。ListView有一個唯一的id:listView1,在MainActivity中將用來引用ListView控件。

  為了創建定制的header,先在你的工程中創建一個新的xml布局文件:listview_header_row.xml,在里面聲明一個TextView控件,屬性值見下面的代碼。將會創建出一個白色字體,藍色背景的header。

 1 listview_header_row.xml文件:  2 <?xml version="1.0" encoding="utf-8"?>
 3 <LinearLayout 
 4     xmlns:android="http://schemas.android.com/apk/res/android"
 5     android:orientation="horizontal" 
 6     android:layout_width="fill_parent"
 7     android:layout_height="fill_parent"> 
 8         
 9      <TextView android:id="@+id/txtHeader"
10         android:layout_width="fill_parent"
11         android:layout_height="fill_parent"
12         android:gravity="center_vertical"
13         android:layout_alignParentTop="true"
14         android:layout_alignParentBottom="true"
15         android:textStyle="bold"
16         android:textSize="22dp"
17         android:textColor="#FFFFFF"
18         android:padding="10dp"
19         android:text="Weather Photos"
20         android:background="#336699" />
21 
22 </LinearLayout>

  為了創建定制的ListView的行樣式,先在你的工程中創建另一個xml布局文件:listview_item_row.xml。Android 會將這個文件的內容傳遞給每個ListView的item,你將可以自由的聲明任何你想添加進里面的控件。本文中,我使用了一個ImageView來顯示天氣圖標和一個TextView來顯示該條item的主題。下面是listview_item_row.xml文件的代碼:

 1 listview_item_row.xml文件:  2 <?xml version="1.0" encoding="utf-8"?>
 3 <LinearLayout 
 4     xmlns:android="http://schemas.android.com/apk/res/android"
 5     android:orientation="horizontal" 
 6     android:layout_width="fill_parent"
 7     android:layout_height="fill_parent"
 8     android:padding="10dp">
 9     
10      <ImageView android:id="@+id/imgIcon"
11         android:layout_width="wrap_content"
12         android:layout_height="fill_parent"
13         android:gravity="center_vertical"
14         android:layout_alignParentTop="true"
15         android:layout_alignParentBottom="true"
16         android:layout_marginRight="15dp"
17         android:layout_marginTop="5dp"
18         android:layout_marginBottom="5dp" />
19         
20      <TextView android:id="@+id/txtTitle"
21         android:layout_width="fill_parent"
22         android:layout_height="fill_parent"
23         android:gravity="center_vertical"
24         android:layout_alignParentTop="true"
25         android:layout_alignParentBottom="true"
26         android:textStyle="bold"
27         android:textSize="22dp"
28         android:textColor="#000000"
29         android:layout_marginTop="5dp"
30         android:layout_marginBottom="5dp" />
31         
32 </LinearLayout>

  本文中,我下載了一些32 X 32像素的PNG格式的圖標。如果你願意,你也可以使用你自己的圖標。准備好你的圖標,放到你工程的drawable-mdpi文件目錄下。接下來,在工程中新建一個java類,命名為Weather.java,這個類將用於創建一個定制的ArrayAdapter來綁定對象到ListView中。下面是Weather.java文件的代碼,它有兩個簡單的屬性icon和title,一個普通的構造函數用於初始化屬性。

二、項目程序開發

  為了方便大家理解,我將程序結構流程畫出來:

            圖3.  重要對象關系結構

 1 Weather.java文件:  2 public class Weather {
 3     public int icon;
 4     public String title;
 5     public Weather(){
 6         super();
 7     }
 8     
 9     public Weather(int icon, String title) {
10         super();
11         this.icon = icon;
12         this.title = title;
13     }
14 }

  注意,上面listview_item_row.xml文件有兩個View,對應於Weather類的兩個屬性。Weather類的屬性值將被顯示到這兩個View中。為了將這兩個View連接起來,你需要創建一個定制的ArrayAdapter,它繼承了Android的ArrayAdapter類,並重寫了getView方法。添加一個新的java類到你的工程中,命名為WeatherAdapter,具體的實現代碼如下:

 1 WeatherAdapter.java文件:  2 public class WeatherAdapter extends ArrayAdapter<Weather>{
 3 
 4     Context context; 
 5     int layoutResourceId;    
 6     Weather data[] = null;
 7     
 8     public WeatherAdapter(Context context, int layoutResourceId, Weather[] data) {
 9         super(context, layoutResourceId, data);
10         this.layoutResourceId = layoutResourceId;
11         this.context = context;
12         this.data = data;
13     }
14 
15     @Override
16     public View getView(int position, View convertView, ViewGroup parent) {
17         View row = convertView;
18         WeatherHolder holder = null;
19         
20         if(row == null)
21         {
22             LayoutInflater inflater = ((Activity)context).getLayoutInflater();
23             row = inflater.inflate(layoutResourceId, parent, false);
24             
25             holder = new WeatherHolder();
26             holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
27             holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
28             
29             row.setTag(holder);
30         }
31         else
32         {
33             holder = (WeatherHolder)row.getTag();
34         }
35         
36         Weather weather = data[position];
37         holder.txtTitle.setText(weather.title);
38         holder.imgIcon.setImageResource(weather.icon);
39         
40         return row;
41     }
42     
43     static class WeatherHolder
44     {
45         ImageView imgIcon;
46         TextView txtTitle;
47     }
48 }

  在上面的代碼中,第一個比較重要的是類的構造函數有三個參數,第一個參數是Context對象(我們可以傳遞當前使用WeatherAdapter類的activity對象的引用,即MainActivity.this對象);第二個參數是resource的id(它是我們想用來呈現每個ListView的item的布局文件的id),在本文中我將傳遞我創建的listview_item_row.xml布局文件的id;第三個參數是一個Weather對象的數組,用於為Adapter適配器提供顯示數據的數據源。

  ArrayAdapter的getView方法被重寫了。這個方法將被ListView每個 item項調用來創建視圖View,它們的屬性是我們設置的。getView方法也使用了一個臨時的holder類(在WeatherAdapter類內部聲明的內部類),這個類將被用於緩存ImageView和TextView,以便它們能夠被ListView中的每行重用,這也會為我們帶來巨大的性能的提升,由於我們不斷地訪問兩個相同的views(ImageView和TextView)的屬性,我們不必為每個ListView的Item查找這兩個控件。上面的代碼也是用了Android內置的LayoutInflator來解析xml布局文件(用於動態加載xml布局文件,以便能夠查找其中的內容)。

  最后一點代碼是我們應用的MainActivity。里面,我們使用了所有上面聲明的對象。下面是MainActivity.java文件的代碼:

 1 MainActivity.java文件:  2 public class MainActivity extends Activity {
 3 
 4     private ListView listView1;
 5 
 6     @Override
 7     public void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.main);
10         
11         Weather weather_data[] = new Weather[]
12         {
13             new Weather(R.drawable.weather_cloudy, "Cloudy"),
14             new Weather(R.drawable.weather_showers, "Showers"),
15             new Weather(R.drawable.weather_snow, "Snow"),
16             new Weather(R.drawable.weather_storm, "Storm"),
17             new Weather(R.drawable.weather_sunny, "Sunny")
18         };
19         
20         WeatherAdapter adapter = new WeatherAdapter(this, 
21                 R.layout.listview_item_row, weather_data);
22         
23         
24         listView1 = (ListView)findViewById(R.id.listView1);
25          
26         View header = (View)getLayoutInflater().inflate(R.layout.listview_header_row, null);
27         listView1.addHeaderView(header);
28         
29         listView1.setAdapter(adapter);
30     }

  MainActivity.java文件中有幾個需要解釋下的地方,以便你能更好的理解。首先,我們創建了一個Weather對象的數組,icon和title被作為參數傳遞給了它的構造函數;接下來,WeatherAdapter對象被創建,listview_item_row.xml文件的id和Weather對象數組被傳遞給了它的構造函數。再一次,我們使用了Android的LayoutInflator來解析listview_item_row.xml布局文件。通過ListView的addHeaderView方法設置ListView的header信息。最后,我們傳遞定制的Adapter給ListView的setAdapter方法。到現在就可以構建、運行工程了。如果一切實現正確,你會看到下面的內容。

      圖2. 運行效果

  最近有一段時間沒寫東西了,真是罪過啊!翻譯之中有不當之處在所難免,大家相互學習。尊重原創,尊重知識,相信分享的力量!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM