讀古今文學網 > Android程序設計:第2版 > 組裝圖形界面 >

組裝圖形界面

Android UI框架提供了一套完整的繪圖工具來構建UI,以及豐富的基於這些工具的預構建的組件組合。正如第8章將介紹的,Android UI框架的圖形工具為應用提供了很多支持,以便應用可以方便地創建自己的控制按鈕或渲染出特殊的視圖。另一方面,很多應用可能只使用工具箱裡的視圖就可以良好工作。實際上,類MapActivity和類MyLocationOverlay可以支持非常複雜的應用的創建,而不需要執行任何自定義渲染。

我們之前已經使用了術語部件,但沒有顯式定義它。屏幕是由組件樹渲染的。在Android UI框架中,這些組件都是android.view.View的子類。在視圖樹中,葉子節點或接近葉子節點的節點執行了大部分的實際渲染工作,在應用UI中,這些節點通常被稱為widget。

內部節點,有時稱為容器視圖(container views),是特殊的組件,可以包含其他子組件。在Android UI框架中,容器視圖是android.view.ViewGroup的子類,它當然也是View的子類。它們通常很少執行渲染工作。相反,它們主要負責安排其子節點在屏幕上的視圖,並且當視圖形狀、方向等改變時,還保持這些節點的位置排列。這些工作實際上很複雜。

要創建複雜的顯示,還需要對應用中要使用的視圖的容器樹進行組裝。例6-1顯示了一個包含三個層次的視圖樹的應用。一個垂直的線性佈局中包含了兩個水平的線性佈局。每個水平佈局又分別包含了兩個部件。

例6-1:一棵複雜的視圖樹


package com.oreilly.android.intro;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
public class AndroidDemo extends Activity {
    private LinearLayout root;
    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        LinearLayout.LayoutParams containerParams
            = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.FILL_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                0.0F);
        LinearLayout.LayoutParams widgetParams
            = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.FILL_PARENT,
                ViewGroup.LayoutParams.FILL_PARENT,
                1.0F);
        root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setBackgroundColor(Color.LTGRAY);
        root.setLayoutParams(containerParams);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setBackgroundColor(Color.GRAY);
        ll.setLayoutParams(containerParams);
        root.addView(ll);
        EditText tb = new EditText(this);
        tb.setText(R.string.defaultLeftText);
        tb.setFocusable(false);
        tb.setLayoutParams(widgetParams);
        ll.addView(tb);
        tb = new EditText(this);
        tb.setText(R.string.defaultRightText);
        tb.setFocusable(false);
        tb.setLayoutParams(widgetParams);
        ll.addView(tb);
        ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setBackgroundColor(Color.DKGRAY);
        ll.setLayoutParams(containerParams);
        root.addView(ll);
        Button b = new Button(this);
        b.setText(R.string.labelRed);
        b.setTextColor(Color.RED);
        b.setLayoutParams(widgetParams);
        ll.addView(b);
        b = new Button(this);
        b.setText(R.string.labelGreen);
        b.setTextColor(Color.GREEN);
        b.setLayoutParams(widgetParams);
        ll.addView(b);
        setContentView(root);
    }
}
  

注意,該代碼保留了視圖樹的根節點的引用,在後面會用到它。

這個例子使用了三個LinearLayout視圖。LinearLayout視圖,正如其名,表示在視圖中根據定位屬性,以行形式或列形式顯示子節點。子視圖的顯示方式和其插入到LinearLayout的順序一致(和其創建的順序無關),其顯示方式對於西方讀者很熟悉:從左到右、至上而下。例如,標籤為Green的按鈕在該佈局的右下角,因為它是第二個插入到水平LinearLayout視圖中的,而這個水平線性視圖又是第二個插入到根節點即垂直的LinearLayout中的。

圖6-2顯示了從用戶角度看的可能結果。樹中的7個視圖是結構化的,如圖6-3所示。

圖6-2:用戶看到的面板

Android框架支持很方便地把數據源和代碼進行分離,這一點對於構建視圖佈局是非常有用的。前一個例子可以被例6-2所示的簡單得多的代碼以及例6-3所示的視圖佈局XML定義所替換。

圖6-3:視圖中的層次

例6-2:使用佈局資源的複雜視圖


package com.oreilly.android.intro;
import android.app.Activity;
import android.os.Bundle;
/**
 * Android UI demo program
 */
public class AndroidDemo extends Activity {
    private LinearLayout root;
    @Override public void onCreate(Bundle state) {
        super.onCreate(state);
        setContentView(R.layout.main);
        root = (LinearLayout) findViewById(R.id.root);
    }    
}
  

例6-3:一個複雜視圖佈局資源的XML定義


<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
    android:id=\"@+id/root\"
    android:orientation=\"vertical\"
    android:background=\"@drawable/lt_gray\"
    android:layout_
    android:layout_>
<LinearLayout
    android:orientation=\"horizontal\"
    android:background=\"@drawable/gray\"
    android:layout_
    android:layout_>
<EditText
      android:id=\"@+id/text1\"
      android:text=\"@string/defaultLeftText\"
      android:focusable=\"false\"
      android:layout_
      android:layout_
      android:layout_weight=\"1\"/>
<EditText
      android:id=\"@+id/text2\"
      android:text=\"@string/defaultRightText\"
      android:focusable=\"false\"
      android:layout_
      android:layout_
      android:layout_weight=\"1\"/>
</LinearLayout>
<LinearLayout
    android:orientation=\"horizontal\"
    android:background=\"@drawable/dk_gray\"
    android:layout_
    android:layout_>
<Button
      android:id=\"@+id/button1\"
      android:text=\"@string/labelRed\"
      android:textColor=\"@drawable/red\"
      android:layout_
      android:layout_
      android:layout_weight=\"1\"/>
<Button
      android:id=\"@+id/button2\"
      android:text=\"@string/labelGreen\"
      android:textColor=\"@drawable/green\"
      android:layout_
      android:layout_
      android:layout_weight=\"1\"/>
</LinearLayout>
</LinearLayout>
  

該版本的代碼和第一個版本的類似,也保留了到視圖樹的根節點的引用。它保留根節點引用的方式是在XML佈局(在這個例子中,即根節點LinearLayout)中給widget打上一個標籤android:id,然後使用Activity類的findViewById方法來獲取引用。

使用資源來定義視圖樹的佈局結構是一個良好的思路。這種方式使我們能夠從代碼中分離出視圖的可視化佈局。修補屏幕佈局就不再需要重新編譯了。然而,更重要的是,你可以使用一些工具來構建自己的UI,採用這種思路你就可以使用可視化UI編輯器編寫屏幕元素。

注意:在Google I/O 2011會議上,Android工具團隊介紹了一種新的編輯器,其功能很令人興奮。它甚至可以預覽動畫和開發人員創建的視圖。大部分開發人員在對視圖進行佈局時不需要查看XML代碼,那些內嵌的代碼被查看的可能就更加渺茫了。