Android開發之旅:深入分析佈局文件

http://blog.csdn.net/muyu114/article/details/6412521


我們這次深入分析Android應用程序的佈局文件,主要內容如下:

  • 1、用戶界面及視圖層次
  • 2、Android中佈局定義方法
  • 3、編寫XML佈局文件及加載XML資源
  • 4、常用佈局文件中元素的屬性
    • 4.1、ID屬性
    • 4.2、佈局參數
  • 5、佈局位置&大小&補距&邊距
  • 6、又是“Hello World!”
    • 6.1、又是“Hello World!”(一)
    • 6.2、又是“Hello World!”(二)
    • 6.3、又是“Hello World!”(三)

1、用戶界面及視圖層次

在通過“Hello World!”介紹Android中的佈局問題之前,不得不先介紹一下Android中的用戶界面,因爲佈局問題也是用戶界面問題之一。在一個Android應用程序中,用戶界面通過ViewViewGroup對象構建。Android中有很多種Views和ViewGroups,他們都繼承自View類。View對象是Android平臺上表示用戶界面的基本單元。

View類:

extends Object
implements Drawable.Callback  KeyEvent.Callback  AccessibilityEventSource

這個類表示用戶界面組件的基本構建塊,一個View佔據屏幕上的一個矩形區域,並負責繪圖和事件處理。View類是widgets的基類,widgets用於創建交互式UI組件(buttons、text fields等)。View類的直接子類ViewGroup類是layouts的基類,layouts是不可見的容器用戶保持其他Views或者其他ViewGroups和定義它們的佈局屬性。

一個View對象是一個數據結構,它的屬性存儲屏幕上一個特定矩形區域的佈局參數內容。一個View對象處理它自己的測度、佈局、繪圖、焦點改變、滾動、鍵/手勢等與屏幕上矩形區域的交互。作爲用戶界面中的對象,View也是與用戶交互的一個點且交互事件接收器。

在Android平臺上,你定義活動的UI使用的View和ViewGroup節點的層次結構如下圖所示。根據你的需要這個層次樹可以是簡單的或複雜的,並且你能使用Android預定義的widgetslayouts集合,或者使用自定義的Views。

viewgroup

圖1、視圖層次結構

爲了將視圖層次樹呈現到屏幕上,你的活動必須調用setContentView()方法並且傳遞到根節點對象的引用。Android系統接收這個引用並使用它來驗證、測度、繪製樹。層次的根節點要求它的孩子節點繪製它自己——相應地每個試圖組節點要求調用自己的孩子視圖去繪製他們自己。子視圖可能在父視圖中請求指定的大小和位置,但是父視圖對象有最終決定權(子視圖在哪個位置及多大)。因爲它們是按序繪製的,如果元素有重疊的地方,重疊部分後面繪製的將在之前繪製的上面。

2、Android中佈局定義方法

佈局是一個活動中的用戶界面的架構,它定義了佈局結構且存儲所有顯示給用戶的元素。有兩種方式可以聲明佈局,這個我們在上文中已經用了(對應上文的“Hello World的手術(二)”、“Hello World的手術(三)”)。我們再重溫總結一下:

  • 方法一、在XML格式的佈局文件中聲明UI。Android提供了簡易的XML詞彙表對應視圖類和其子類,諸如widgetslayouts
  • 方法二、在運行時實例化佈局元素。可以編程地創建View和ViewGroup對象,並操作他們的屬性。

Android框架給我們靈活地使用這兩個方法之一或兩個聲明和管理你的應用程序的UI。例如,你可以用XML格式的佈局文件定義應用程序默認的佈局,包括將顯示在屏幕的元素和屬性。然後你可以編程地修改屏幕上對象的狀態,包括定義在XML文件中的元素。

最常用的是方法一,即用一個XML的佈局文件定義自己的佈局和表達層次視圖。XML提供一種直觀的佈局結構,類似HTML。XML中的每個元素是一個View或者ViewGroup對象(或繼承自他們的對象)。View對象是樹中的葉子,ViewGroup對象是樹中的分支,這點可以從上面的視圖層次樹中可以看出。

在XML佈局文件中聲明UI的優點是:使應用程序的界面控制它行爲的代碼更好地分離了。UI描述在應用程序代碼之外,這意味着你可以修改或調整它而不用修改你的源碼並重新編譯。例如,你可以爲不同的屏幕方向、不同的屏幕大小、不同的語言創建XML佈局文件。此外,在XML中聲明佈局更易地可視化你的UI結構,因此更容易調試問題。

一個元素XML元素的名字對應到一個Java類,因此一個<TextView>元素在你的UI中創建一個TextView,一個<linearLayout>元素創建一個LinearLayout的視圖組。當你加載一個佈局資源時,Android系統初始化這些運行時對象,對應你的佈局中的元素。XML元素的屬性對應到一個Java類的方法。

3、編寫XML佈局文件及加載XML資源

使用Android的XML詞彙,我們可以快速地設計UI佈局及包含的屏幕元素,就像web頁面的HTML。每個佈局文件必須包含一個根元素,根元素必須是一個View或ViewGroup對象。一旦你已經定義了根元素,你可以添加額外的layout對象或widgets作爲子元素,逐步地構建一個視圖層次定義你的佈局。例如,下面的XML佈局文件使用了縱向的LinearLayout保存一個TextView和一個Button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical">
    <TextViewandroid:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView"/>
    <Buttonandroid:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button"/>
</LinearLayout>

佈局文件以.xml爲擴展名,保存在res/layout/下面,它將會被正確地編譯。我們已經定義好了佈局文件,那它是怎麼被加載的呢?當我們編譯應用程序時,每個XML佈局文件被編譯成一個View資源。我們應該在應用程序代碼中加載佈局資源,在Activity.onCreate()回調中通過調用setContentView()實現,以R.layout.layout_file_name 形式傳遞給它佈局資源的引用。例如,如果你的XML佈局保存爲main_layout.xml,你應該這樣加載它:
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView.(R.layout.main_layout);
}
活動中的onCreate()回調方法,當你的活動啓動時被Android框架調用(詳見Android 開發之旅:組件生命週期(一),詳細介紹了活動組件的生命週期)。

4、常用佈局文件中元素的屬性

每個View和ViewGroup對象支持他們自己的各種XML屬性。一些屬性特定於一個View對象(例如,TextView支持textSize屬性),但是這些屬性也被繼承自這個類的任何View對象繼承。一些屬性對所有View對象可用,因爲他們從根View類繼承(諸如id屬性)。並且,其他屬性被考慮爲“佈局參數”,這些屬性描述特定View對象的特定佈局方向,由對象的父ViewGroup對象定義。

4.1、ID屬性

每個View對象都有一個關聯的ID,來唯一標識它。當應用程序被編譯時,這個ID作爲一個整數引用。但是ID通常是在佈局XML文件中作爲字符串分配的,作爲元素的id屬性。這個XML屬性對所有的View對象可用且會經常用到。XML中的ID語法如下:

android:id="@+id/my_button"

字符串前的@符號表示XML解析器應該解析和擴展剩下的ID字符串,並把它作爲ID資源。+符號表示這是一個新的資源名字,它必須被創建且加入到我們的資源(R.java文件,R是Resource)。Android框架提供一些其他的ID資源。當引用一個 Android資源ID時,你不需要+符號,但是你必須添加android包名字空間,如下:

android:id="@android:id/empty"

爲了創建視圖和從應用程序引用他們,通常的模式是:

  1. 首先在佈局文件中定義一個視圖/構件對象並分配一個唯一的ID:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
  2. 然後創建一個視圖對象實例並從佈局中獲取它(典型的是在onCreate()方法中):
    Button myButton = (Button) findViewById(R.id.my_button);

4.2、佈局參數

名爲layout_something的XML佈局屬性,爲視圖定義適合於它所駐留的ViewGroup的佈局參數。每個ViewGroup類實現一個擴展自ViewGroup.LayoutParams的嵌套類。這個子類包含爲每個子視圖定義大小位置的屬性類型,以適合於該視圖組。如下圖所示,父視圖組爲每個子視圖定義佈局參數(包括子視圖組)。

layoutparams   
圖2、佈局參數

注意每個LayoutParams子類有它自己的設置值的語法。每個子元素必須定義適合於它父視圖的LayoutParams,雖然它可能也爲自己的子視圖定義不同LayoutParams。

所有的視圖組包括寬帶和高度(layout_widthlayout_height),並且每個視圖要求要定義它們。許多LayoutParams也包括可選的邊距和邊界。你可以指定寬度和高度的具體值,雖然你可能並不想這樣做。更多地你將告訴視圖它的大小依據它內容要求或跟父視圖組所允許的一樣大(分別用wrap_contentfill_parent值)。

5、佈局位置&大小&補距&邊距

視圖的幾何形狀是一個矩形。視圖的位置表示爲一個left和top的座標對,尺寸(dimensions)表示爲寬度和高度。位置和尺寸的單位是像素(pixel)。

可以通過調用getLeft()getTop()檢索視圖的位置。前者返回視圖矩形座標的left或x,後者返回視圖矩形座標的right或y。這些方法返回相對於與其父視圖的相對位置,例如當getLeft()返回20,即認爲視圖到其直接父視圖的左邊距離爲20像素。

此外,提供了一些額外的方法如getRight()getButtom()避免不必要的計算。這些方法返回視圖座標的右邊距和底邊距。例如,調用getRight()等同於下面的計算:getLeft()+getWidth()

視圖的大小(size)也表示爲寬度和高度,但跟上面尺寸(dimensions)是區別的。上面的尺寸定義視圖想在父視圖中佔多大,視圖的尺寸可以通過getMeasureWidth()getMeasureHeight()獲得。而視圖的大小(size)則表示視圖在屏幕上的實際大小,他們的值可以跟視圖尺寸的不一樣,但也不是非得這樣。視圖的大小可以通過getWidth()getHeight()獲得。

爲了估量視圖的尺寸,必須考慮它的補距(padding,即視圖內容與視圖邊框的距離)。補距以像素表示視圖的left、top、right和bottom部分的空白。補距可以用來按特定數量的像素偏移視圖內容。例如,左補距是2將輸出內容離左邊框2像素。補距可以通過setPadding(int, int, int, int)方法設置和通過getPaddingLeft()getPaddingRight()getPaddingTop()getPaddingBottom()來查詢。雖然一個視圖可以定義補距,但是它不支持邊距(margins)。然而,視圖組支持邊距。

6、又是“Hello World!”

下面我們通過幾個實驗來驗證和加深上述關於佈局文件理解。

6.1、又是“Hello World!”(一)

驗證名爲layout_something的XML佈局屬性,用layout_widthlayout_height定義Button的寬度和高度,這兩個屬性也是每個視圖對象都必須要聲明定義的。驗證wrap_content與fill_parent的區別,其實區別從他們的單詞組成就可以看出:wrap——包,包裹等而content——內容,則wrap_content表示視圖對象的高度/寬度正好包住內容;fill——填充等而parent——父,則fill_parent表示填滿父視圖。

實驗設置爲:在佈局資源文件中定義兩個Button,id分別爲button1、button2,button1的寬度和高度屬性都是wrap_content,button2的寬度和高度屬性都是fill_parent。main.xml文件代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical">
    <Buttonandroid:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button"/>
    <Buttonandroid:id="@+id/button2"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:text="Hello, I am a Button"
    />
</LinearLayout>
而HelloWorld.java文件代碼爲:
package skynet.com.cnblogs.www;

import android.app.Activity;
import android.os.Bundle;
import android.widget.*;//注意:導入此包,或者是android.widget.Button;

public class HelloWorldextends Activity {
    private CharSequence text="new Hello!";

/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}
運行可以得到如下圖結果:

又見HelloWorld1

圖3、驗證 驗證名爲layout_something的XML佈局屬性

明顯可以看出button1的大小是剛好包住內容“Hello,I am a Button”,而button2的大小則是填滿父視圖的大小。

6.2、又是“Hello World!”(二)

接下來我們視圖對象的通用屬性ID及再次驗證定義佈局的兩種方式。(關於ID屬性——首先在佈局文件中定義一個視圖/構件對象並分配一個唯一的ID,然後創建一個視圖對象實例並從佈局中獲取它(典型的是在onCreate()方法中))。

屬性實驗設置爲:基本跟上面一樣,但是我們要編程地修改button1的text屬性。main.xml佈局文件跟上面一樣,而主要是HelloWorld.java文件不一樣,它的代碼如下:
package skynet.com.cnblogs.www;

import android.app.Activity;
import android.os.Bundle;
//import android.widget.*;
import android.widget.Button;

public class HelloWorldextends Activity {
    private CharSequence text="new Hello!";

/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button myButton=(Button)findViewById(R.id.button2);
        myButton.setText(text);

    }
}
上面紅色粗體的兩行代碼就是編程地改變button2的text屬性,這體現了Android框架給我們靈活地使用上面兩個方法之一或兩個聲明和管理你的應用程序的UI。運行結果如下圖所示:

又見HelloWorld2

圖4、驗證視圖對象的通用屬性Id的常用模式及編程地改變定義在XML佈局文件中的Button的屬性

6.3、又是“Hello World!”(三)

 

 

驗證視圖對象的佈局位置&大小&補距,實驗設置爲:在實驗一的基礎上在main.xml中修改button1的佈局位置、大小、補距等屬性。修改後的mian.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical">
    <Buttonandroid:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"           
            android:text="Hello, I am a Button"
            android:width="250dp"
            android:height="80dp"
            android:padding="20dp"
            android:layout_margin="20dp"

            />
    <Buttonandroid:id="@+id/button2"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:text="Hello, I am a Button"
    />
</LinearLayout>
運行後結果如下所示:

又見HelloWorld3

圖5、 驗證視圖對象的佈局位置&大小&補距

NOTE:上述代碼中佈局位置&大小&補距的單位(如width="250dp")。單位可以爲px、in、mm、pt、dp、sp。

  • px:pixels(像素)——對應屏幕上實際的像素
  • in:inches(英寸)——基於物理屏幕的大小
  • mm:millimeters(毫米)——基於物理屏幕的大小
  • pt:points(點)——英寸的1/72,基於基於物理屏幕的大小
  • dp:density-independent pixels(獨立於密度的像素)——一個抽象的基於物理屏幕密度的單位。這些單位是相對於一個160dpi的屏幕,所有一個dp是160dpi屏幕上的一個點。dp到px的轉換比率根據屏幕密度改變,但不一定是成正比。
  • sp:scale-independent pixels(規模獨立像素)——類似於dp單位,但是它也受用戶字體大小設置的影響。當你指定字體大小時使用它,因爲他們將根據屏幕和用戶設置調整。

轉自:http://www.cnblogs.com/skynet/archive/2010/05/20/1740277.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章