Android入門(五)UI-單位與尺寸、ListView

來源:互聯網
上載者:User

標籤:

原文連結:http://www.orlion.ga/453/

一、單位與尺寸

    布局檔案中一共有以下單位供選擇:px,pt,dp,sp

    px:是像素,螢幕中可見的最小元素單位。

    pt:是磅,1磅等於1/72英寸,一般pt都會作為字型的單位來使用。

    同樣px數的控制項在不同解析度上的手機螢幕上的效果是不同的,pt與px的情況差不多

 

    dp:是密度無關像素,也稱為dip,與px相比,它在不同密度的螢幕中的顯示比例保持一致

    sp:是可伸縮像素,採用了與dp同樣的設計理念,解決了文字大小的適配問題

 

    android中的密度就是螢幕沒英寸所包含的像素數,通常以dpi為單位,比如一個手機螢幕的寬是2英寸長是3英寸,如果它的解析度是320*480像素,那這個手機的螢幕就是160dpi,如果分辨是640*960,那麼這個螢幕的密度就是320dpi。

    根據Android的規定,在160dpi的螢幕上1dp等於1px,而在320dpi的螢幕上1dp就等於2px。

 

二、ListView
    

    1、ListView的簡單用法

    首先建立一個 ListViewTest 項目,並讓 ADT 自動幫我們建立好活動。然後修改

activity_main.xml中的代碼,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <ListView        android:id="@+id/list_view"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </ListView></LinearLayout>

    接下來修改 MainActivity中的代碼,如下所示:

public class MainActivity extends Activity {    private String[] data = { "Apple", "Banana", "Orange", "Watermelon",        "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango" };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ArrayAdapter<String> adapter = new ArrayAdapter<String>(            MainActivity.this, android.R.layout.simple_list_item_1, data);        ListView listView = (ListView) findViewById(R.id.list_view);        listView.setAdapter(adapter);    }}

    

    既然ListView是用於展示大量資料的,那我們就應該先將資料提供好。這些資料可以是從網上下載的,也可以是從資料庫中讀取的,應該視具體的應用程式情境來決定。這裡我們就簡單使用了一個 data數組來測試,裡麵包含了很多水果的名稱。

    不過,數組中的資料是無法直接傳遞給 ListView的,我們還需要藉助適配器來完成。Android中提供了很多適配器的實作類別,其中我認為最好用的就是 ArrayAdapter。它可以通過泛型來指定要適配的資料類型, 然後在建構函式中把要適配的資料傳入即可。 ArrayAdapter有多個建構函式的重載,你應該根據實際情況選擇最合適的一種。這裡由於我們提供的資料都是字串,因此將 ArrayAdapter的泛型指定為 String,然後在 ArrayAdapter的建構函式中依次傳入當前上下文、ListView 子項布局的 id,以及要適配的資料。注意我們使用了android.R.layout.simple_list_item_1作為 ListView子項布局的 id,這是一個 Android內建的布局檔案, 裡面只有一個 TextView, 可用於簡單地顯示一段文本。 這樣配接器物件就構建好了。最後,還需要調用 ListView的 setAdapter()方法,將構建好的配接器物件傳遞進去,這樣 ListView和資料之間的關聯就建立完成了。現在運行一下程式,

    2、給ListView加圖片

    只能顯示一段文本的 ListView實在是太單調了,我們現在就來對 ListView的介面進行定製,讓它可以顯示更加豐富的內容。首先需要準備好一組圖片,分別對應上面提供的每一種水果,待會我們要讓這些水果名稱的旁邊都有一個圖樣。接著定義一個實體類,作為 ListView適配器的適配類型。建立類 Fruit,代碼如下所示:

public class Fruit {    private String name;    private int imageId;    public Fruit(String name, int imageId) {        this.name = name;        this.imageId = imageId;    }    public String getName() {        return name;    }    public int getImageId() {        return imageId;    }}

    

    Fruit類中只有兩個欄位,name表示水果的名字,imageId表示水果對應圖片的資源 id。然後需要為 ListView 的子項指定一個我們自訂的布局,在 layout 目錄下建立fruit_item.xml,代碼如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <ImageView        android:id="@+id/fruit_image"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/fruit_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:layout_marginLeft="10dip" /></LinearLayout>

    在這個布局中,我們定義了一個 ImageView 用於顯示水果的圖片,又定義了一個TextView用於顯示水果的名稱。

接下來需要建立一個自訂的適配器,這個適配器繼承自 ArrayAdapter,並將泛型指定為 Fruit類。建立類 FruitAdapter,代碼如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {    private int resourceId;    public FruitAdapter(Context context, int textViewResourceId,        List<Fruit> objects) {        super(context, textViewResourceId, objects);        resourceId = textViewResourceId;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        Fruit fruit = getItem(position); // 擷取當前項的Fruit執行個體        View view = LayoutInflater.from(getContext()).inflate(resourceId, null);        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);        fruitImage.setImageResource(fruit.getImageId());        fruitName.setText(fruit.getName());        return view;    }}

    FruitAdapter重寫了父類的一組建構函式,用於將上下文、ListView子項布局的 id和資料都傳遞進來。另外又重寫了 getView()方法,這個方法在每個子項被滾動到螢幕內的時候會被調用。在 getView方法中,首先通過 getItem()方法得到當前項的 Fruit執行個體,然後使用LayoutInflater來為這個子項載入我們傳入的布局, 接著調用 View的 findViewById()方法分別擷取到 ImageView和 TextView的執行個體,並分別調用它們的 setImageResource()和 setText()方法來設定顯示的圖片和文字,最後將布局返回,這樣我們自訂的適配器就完成了。下面修改 MainActivity中的代碼,如下所示:

public class MainActivity extends Activity {    private List<Fruit> fruitList = new ArrayList<Fruit>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initFruits(); // 初始化水果資料        FruitAdapter adapter = new FruitAdapter(MainActivity.this,        R.layout.fruit_item, fruitList);        ListView listView = (ListView) findViewById(R.id.list_view);        listView.setAdapter(adapter);    }    private void initFruits() {        Fruit apple = new Fruit("Apple", R.drawable.apple_pic);        fruitList.add(apple);        Fruit banana = new Fruit("Banana", R.drawable.banana_pic);        fruitList.add(banana);        Fruit orange = new Fruit("Orange", R.drawable.orange_pic);        fruitList.add(orange);        Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);        fruitList.add(watermelon);        Fruit pear = new Fruit("Pear", R.drawable.pear_pic);        fruitList.add(pear);        Fruit grape = new Fruit("Grape", R.drawable.grape_pic);        fruitList.add(grape);        Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);        fruitList.add(pineapple);        Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);        fruitList.add(strawberry);        Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);        fruitList.add(cherry);        Fruit mango = new Fruit("Mango", R.drawable.mango_pic);        fruitList.add(mango);    }}

    可以看到,這裡添加了一個 initFruits()方法,用於初始化所有的水果資料。在 Fruit類的建構函式中將水果的名字和對應的圖片 id傳入,然後把建立好的對象添加到水果列表中。接著我們在 onCreate()方法中建立了 FruitAdapter對象,並將 FruitAdapter作為適配器傳遞給了 ListView。這樣定製 ListView介面的任務就完成了。現在重新運行程式

,

    3、提升ListView的運行效率

    之所以說 ListView這個控制項很難用,就是因為它有很多的細節可以最佳化,其中運行效率就是很重要的一點。 目前我們ListView的運行效率是很低的, 因為在FruitAdapter的getView()方法中每次都將布局重新載入了一遍,當 ListView快速滾動的時候這就會成為效能的瓶頸。仔細觀察,getView()方法中還有一個 convertView參數,這個參數用於將之前載入好的

布局進行緩衝,以便之後可以進行重用。修改 FruitAdapter中的代碼,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {    ……    @Override    public View getView(int position, View convertView, ViewGroup parent) {        Fruit fruit = getItem(position);        View view;        if (convertView == null) {            view = LayoutInflater.from(getContext()).inflate(resourceId, null);        } else {            view = convertView;        }        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);        fruitImage.setImageResource(fruit.getImageId());        fruitName.setText(fruit.getName());        return view;    }}

    可以看到,現在我們在 getView()方法中進行了判斷,如果 convertView為空白,則使用LayoutInflater去載入布局,如果不為空白則直接對 convertView進行重用。這樣就大大提高了ListView的運行效率,在快速滾動的時候也可以表現出更好的效能。

不過, 目前我們的這份代碼還是可以繼續最佳化的, 雖然現在已經不會再重複去載入布局,但是每次在getView()方法中還是會調用View的findViewById()方法來擷取一次控制項的執行個體。我們可以藉助一個 ViewHolder來對這部分效能進行最佳化,修改 FruitAdapter中的代碼,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {    ……    @Override    public View getView(int position, View convertView, ViewGroup parent) {        Fruit fruit = getItem(position);        View view;        ViewHolder viewHolder;        if (convertView == null) {            view = LayoutInflater.from(getContext()).inflate(resourceId, null);            viewHolder = new ViewHolder();            viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);            viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);            view.setTag(viewHolder); // 將ViewHolder儲存在View中        } else {            view = convertView;            viewHolder = (ViewHolder) view.getTag(); // 重新擷取ViewHolder        }        viewHolder.fruitImage.setImageResource(fruit.getImageId());        viewHolder.fruitName.setText(fruit.getName());        return view;    }    class ViewHolder {        ImageView fruitImage;        TextView fruitName;    }}

    我們新增了一個內部類 ViewHolder,用於對控制項的執行個體進行緩衝。當 convertView為空白的時候, 建立一個 ViewHolder對象, 並將控制項的執行個體都存放在 ViewHolder裡, 然後調用 View的 setTag()方法,將 ViewHolderObject Storage Service在 View中。當 convertView不為空白的時候則調用View的 getTag()方法, 把 ViewHolder重新取出。 這樣所有控制項的執行個體都緩衝在了 ViewHolder裡,就沒有必要每次都通過 findViewById()方法來擷取控制項執行個體了。通過這兩步的最佳化之後,我們 ListView的運行效率就已經非常不錯了。

 

    4、ListView的點擊事件

    ListView的滾動畢竟只是滿足了我們視覺上的效果,可是如果 ListView中的子項不能點擊的話,這個控制項就沒有什麼實際的用途了。因此,本小節中我們就來學習一下ListView如何才能響應使用者的點擊事件。修改 MainActivity中的代碼,如下所示:

public class MainActivity extends Activity {    private List<Fruit> fruitList = new ArrayList<Fruit>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initFruits();        FruitAdapter adapter = new FruitAdapter(MainActivity.this,        R.layout.fruit_item, fruitList);        ListView listView = (ListView) findViewById(R.id.list_view);        listView.setAdapter(adapter);        listView.setOnItemClickListener(new OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                int position, long id) {                Fruit fruit = fruitList.get(position);                Toast.makeText(MainActivity.this, fruit.getName(),                Toast.LENGTH_SHORT).show();            }        });    }    ……}

    

    可以看到,我們使用了 setOnItemClickListener()方法來為 ListView註冊了一個監聽器,當使用者點擊了 ListView中的任何一個子項時就會回調 onItemClick()方法, 在這個方法中可以通過 position參數判斷出使用者點擊的是哪一個子項,然後擷取到相應的水果,並通過 Toast將水果的名字顯示出來。重新運行程式,並點擊一下西瓜

 

Android入門(五)UI-單位與尺寸、ListView

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.