天天看點

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

以說是一個分水嶺,它标志着我們從android應用程式理論進入實踐,我們拿起手術刀對預設的“hello

world!”程式進行了3個手術,我們清楚了“hello

world!”是如何實作顯示在螢幕上的,而且我們知道不僅可以根據布局檔案main.xml來初始化螢幕,還可程式設計地進行。以後基本我們都會以實踐的方

式來深入android開發。我們這次深入分析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!”(三)

在通過“hello world!”介紹android中的布局問題之前,不得不先介紹一下android中的使用者界面,因為布局問題也是使用者界面問題之一。在一個android應用程式中,使用者界面通過view和viewgroup對象建構。android中有很多種views和viewgroups,他們都繼承自view類。view對象是android平台上表示使用者界面的基本單元。

view類: 這個類表示使用者界面元件的基本建構塊,一個view占據螢幕上的一個矩形區域,并負責繪圖和事件處理。view類是widgets的基類,widgets用于建立互動式ui元件(buttons、text fields等)。view類的直接子類viewgroup類是layouts的基類,layouts是不可見的容器使用者保持其他views或者其他viewgroups和定義它們的布局屬性。

一個view對象是一個資料結構,它的屬性存儲螢幕上一個特定矩形區域的布局參數和内容。一個view對象處理它自己的測度、布局、繪圖、焦點改變、滾動、鍵/手勢等與螢幕上矩形區域的互動。作為使用者界面中的對象,view也是與使用者互動的一個點且互動事件接收器。

在android平台上,你定義活動的ui使用的view和viewgroup節點的層次結構如下圖所示。根據你的需要這個層次樹可以是簡單的或複雜的,并且你能使用android預定義的widgets和layouts集合,或者使用自定義的views。

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

圖1、視圖層次結構

為了将視圖層次樹呈現到螢幕上,你的活動必須調用setcontentview()方

法并且傳遞到根節點對象的引用。android系統接收這個引用并使用它來驗證、測度、繪制樹。層次的根節點要求它的孩子節點繪制它自己——相應地每個試

圖組節點要求調用自己的孩子視圖去繪制他們自己。子視圖可能在父視圖中請求指定的大小和位置,但是父視圖對象有最終決定權(子視圖在哪個位置及多大)。因

為它們是按序繪制的,如果元素有重疊的地方,重疊部分後面繪制的将在之前繪制的上面。

方法一、在xml格式的布局檔案中聲明ui。android提供了簡易的xml詞彙表對應視圖類和其子類,諸如widgets和layouts。

方法二、在運作時執行個體化布局元素。可以程式設計地建立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類的方法。

使用android的xml詞彙,我們可以快速地設計ui布局及包含的螢幕元素,就像web頁面的html。每個布局檔案必須包含一個根元素,根元素必須是一個view或viewgroup對象。一旦你已經定義了根元素,你可以添加額外的layout對象或widgets作為子元素,逐漸地建構一個視圖層次定義你的布局。例如,下面的xml布局檔案使用了縱向的linearlayout儲存一個textview和一個button。

<?xml version="1.0" encoding="utf-8"?>

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:layout_width="fill_parent"

              android:layout_height="fill_parent"

              android:orientation="vertical" >

    <textview android:id="@+id/text"

              android:layout_width="wrap_content"

              android:layout_height="wrap_content"

              android:text="hello, i am a textview" />

    <button android: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);

}

每個view和viewgroup對象支援他們自己的各種xml屬性。一些屬性特定于一個view對象(例如,textview支援textsize屬性),但是這些屬性也被繼承自這個類的任何view對象繼承。一些屬性對所有view對象可用,因為他們從根view類繼承(諸如id屬性)。并且,其他屬性被考慮為“布局參數”,這些屬性描述特定view對象的特定布局方向,由對象的父viewgroup對象定義。

每個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"

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

首先在布局檔案中定義一個視圖/構件對象并配置設定一個唯一的id:

<button android:id="@+id/my_button"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/my_button_text"/>

然後建立一個視圖對象執行個體并從布局中擷取它(典型的是在oncreate()方法中):

button mybutton = (button) findviewbyid(r.id.my_button);

名為layout_something的xml布局屬性,為視圖定義适合于它所駐留的viewgroup的布局參數。每個viewgroup類實作一個擴充自viewgroup.layoutparams的嵌套類。這個子類包含為每個子視圖定義大小和位置的屬性類型,以适合于該視圖組。如下圖所示,父視圖組為每個子視圖定義布局參數(包括子視圖組)。

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

圖2、布局參數

注意每個layoutparams子類有它自己的設定值的文法。每個子元素必須定義适合于它父視圖的layoutparams,雖然它可能也為自己的子視圖定義不同layoutparams。

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

視圖的幾何形狀是一個矩形。視圖的位置表示為一個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)。然而,視圖組支援邊距。

下面我們通過幾個實驗來驗證和加深上述關于布局檔案了解。

驗證名為layout_something的xml布局屬性,用layout_width和layout_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檔案代碼如下:

    <button android:id="@+id/button1"

    <button android:id="@+id/button2"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:text="hello, i am a button"

    />

而helloworld.java檔案代碼為:

package skynet.com.cnblogs.www;

import android.app.activity;

import android.os.bundle;

import android.widget.*;//注意:導入此包,或者是android.widget.button;

public class helloworld extends 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);

    }

運作可以得到如下圖結果:

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

圖3、驗證 驗證名為layout_something的xml布局屬性

明顯可以看出button1的大小是剛好包住内容“hello,i am a button”,而button2的大小則是填滿父視圖的大小。

接下來我們視圖對象的通用屬性id及再次驗證定義布局的兩種方式。(關于id屬性——首先在布局檔案中定義一個視圖/構件對象并配置設定一個唯一的id,然後建立一個視圖對象執行個體并從布局中擷取它(典型的是在oncreate()方法中))。

屬性實驗設定為:基本跟上面一樣,但是我們要程式設計地修改button1的text屬性。main.xml布局檔案跟上面一樣,而主要是helloworld.java檔案不一樣,它的代碼如下:

//import android.widget.*;

import android.widget.button;

        button mybutton=(button)findviewbyid(r.id.button2);

        mybutton.settext(text);

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

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

圖4、驗證視圖對象的通用屬性id的常用模式及程式設計地改變定義在xml布局檔案中的button的屬性

驗證視圖對象的布局位置&大小&補距,實驗設定為:在實驗一的基礎上在main.xml中修改button1的布局位置、大小、補距等屬性。修改後的mian.xml檔案如下:

            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"

            />

運作後結果如下所示:

Android 開發之旅:深入分析布局檔案&又是“Hello World!”

圖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機關,但是它也受使用者字型大小設定的影響。當你指定字型大小時使用它,因為他們将根據螢幕和使用者設定調整。

繼續閱讀