3) 十分鐘學會android--建立第一個APP,建立簡單的用戶界面
在本小節裏,我們將學習如何用 XML 創建一個帶有文本輸入框和按鈕的界面。下一節課將學會使 APP 對按鈕做出響應——按鈕被按下時,文本框裏的內容被發送到另外一個 Activity。
Android 的圖形用戶界面由多個視圖(View)和視圖組(ViewGroup)構建而成。View 是通用的 UI 窗體小組件,如:按鈕(Button)、文本框(Text field);而 ViewGroup 則是用來定義子視圖布局的不可見的容器,如:網格部件(grid)、垂直列表部件(vertical list)。
Android 提供了一系列對應於 View 和 ViewGroup 子類的 XML 標簽,以便我們用 XML 創建自己的 UI。
Layouts 是 ViewGroup 的子類。我們將在接下來的教程中練習如何使用 LinearLayout。
圖 1 關於 ViewGroup 對象如何組織布局分支和包含其他 View 對象。
可選的布局文件
有很多理由使得我們選擇在 XML 中定義界面布局,而不是在運行時動態生成布局。其中最重要的一點是——這可以讓你為不同大小的屏幕創建不同的布局文件。例如,你可以創建兩個版本的布局文件,告訴系統在小屏幕上使用其中一個布局文件,在大屏幕上使用另外一個布局文件。參見 兼容不同的設備。
創建一個 LinearLayout
-
在 Android Studio 中,從
res/layout
content_my.xml
文件。上一節創建新項目時生成的 BlankActivity 包含一個
content_my.xml
文件,該文件根元素是一個包含 TextView 的 RelativeLayout。 -
在 Preview 面板點擊 關閉右側 Preview 面板。
在 Android Studio 中打開布局文件時,可以看到一個 Preview 面板。點擊這個面板中的標簽,可利用 WYSIWYG(所見即所得)工具在 Design 面板看到對應的圖形化效果。但在本節中,我們將學習如何直接修改 XML 文件。
-
刪除 [<TextView>] 標簽。
-
把 [<RelativeLayout>] 標簽改為 [<LinearLayout>]。
-
為 [<LinearLayout>] 添加 android:orientation 屬性並設置值為
"horizontal"
。 -
去掉
android:padding
屬性和tools:context
屬性。
修改後結果如下:
res/layout/content_my.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_my">
LinearLayout 是 ViewGroup 的子類,用於放置水平或者垂直方向的子視圖部件,放置方向由屬性 android:orientation 決定。LinearLayout 裏的子布局按照 XML 裏定義的順序顯示在屏幕上。
所有的 Views 都會用到 android:layout_width 和 android:layout_height 這兩個屬性來設置自身的大小。
由於 LinearLayout 是整個視圖的根布局,所以通過指定 width 和 height 屬性為 "match_parent"
可以使其寬度和高度充滿整個屏幕。該值表示子 View 擴張自己寬度和高度來 匹配 父控件的寬度和高度。
更多關於布局屬性的內容,請參考 布局向導。
添加一個文本輸入框
與其它 View 一樣,我們需要定義 XML 裏的某些屬性來指定 EditText 的屬性值。以下是應該在線性布局裏指定的一些屬性元素:
-
在
content_my.xml
文件的 [<LinearLayout>] 標簽內定義一個 [<EditText>] 標簽,並設置id
屬性為@+id/edit_message
。 -
設置
layout_width
和layout_height
屬性為wrap_content
。 -
設置
hint
屬性為一個名為edit_message
的字符串。
代碼如下:
res/layout/content_my.xml
<EditText android:id="@+id/edit_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />
各屬性說明:
android:id
這是視圖的唯一標識符。可以在程序代碼中通過該標識符引用對象。例如對這個對象進行讀和修改的操作(在下一課裏將會用到)。
當需要從 XML 裏引用資源對象時,必須使用 @
符號。緊隨 @
之後的是資源的類型(這裏是 id
),然後是資源的名字(這裏使用的是 edit_message
)。
+
號只在第一次定義一個資源 ID 的時候需要。它是告訴 SDK——此資源 ID 需要被創建。在應用程序被編譯之後,SDK 就可以直接使用這個 ID。edit_message 是在項目文件 gen/R.java
中創建一個新的標識符,這個標識符和 EditText 關聯。一旦資源 ID 被創建了,其他資源如果引用這個 ID 就不再需要 +
號。
android:layout_width 和 android:layout_height
不建議指定寬度和高度的具體尺寸,應使用 "wrap_content"
。因為這樣可以保證視圖只占據內容大小的空間。如果你使用了 "match_parent"
,這時 EditText 將會布滿整個屏幕,因為它將適應父布局的大小。參見 布局向導。
android:hint
當文本框為空的時候,會默認顯示這個字符串。對於字符串 "@string/edit_message"
的值所引用的資源應該定義在單獨的文件裏,而不是直接使用字符串。因為使用的值是存在的資源,所以不需要使用 +
號。當然,由於你現在還沒有定義字符串,所以在添加 @string/edit_message
的時候會出現編譯錯誤。在下一節的教程中你將學會如何定義字符串資源,到時候就不會報錯了。
資源對象
資源對象是與 APP 資源(如:位圖、布局文件、字符串)關聯的唯一整數。
在項目文件
gen/R.java
中,每個資源都有一個與之對應的資源對象。你可以使用R
類中的對象名稱代指資源(如:在指定 android:hint 屬性時需要的字符串)。同時,也可以通過 android:id 屬性隨時為 View 創建資源 ID,以便在代碼中引用這個 View。每次編譯 APP 時,SDK 工具都會生成
R.java
文件。所以,請永遠不要修改這個文件。參閱 資源配備。
註:該字符串資源與 ID 使用了相同的名稱(
edit_message
)。然而,對於資源的引用是區分類型的(比如id
和字符串
),因此,使用相同的名稱不會引起沖突。
增加字符串資源
默認情況下,你的 Android 項目包含一個字符串資源文件,即 res/values/string.xml
。打開這個文件,為 "edit_message"
增加一個定義,其值為“Enter a message”。
-
在 Android Studio 裏,編輯
res/values
下的strings.xml
文件。 -
添加一個名為
"edit_message"
的字符串,值為“Enter a message”。 -
再添加一個名為
"button_send"
的字符串,值為“Send”。下一節中將使用這個字符串創建按鈕。
下邊就是修改好的 res/values/strings.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My First App</string>
<string name="edit_message">Enter a message</string>
<string name="button_send">Send</string>
<string name="action_settings">Settings</string>
</resources>
當你在用戶界面定義一個文本時,應該把每一個文本字符串列入資源文件。這樣做的好處是:對於所有字符串值,字符串資源能夠單獨的修改,在資源文件裏你可以很容易的找到並且做出相應的修改。通過選擇定義每個字符串,還允許你用不同語言本地化 APP。
更多關於不同語言本字符串資源本地化的問題,請參考 兼容不同的設備。
添加一個按鈕
-
在 Android Studio 裏,編輯
res/layout
下的content_my.xml
文件。 -
在 [<LinearLayout>] 內部的 [<EditText>] 標簽之後定義一個 [<Button>] 標簽。
-
設置按鈕的 width 和 height 屬性值為
"wrap_content"
以便讓按鈕的大小能完整顯示文字。 -
定義按鈕的文本使用 android:text 屬性,設置值為相似上一節中定義好的
button_send
字符串資源。
此時的 [<LinearLayout>] 看起來應該是這樣:
res/layout/content_my.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_my">
<EditText android:id="@+id/edit_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send" />
</LinearLayout>
註:寬和高被設置為
"wrap_content"
,這時按鈕占據的大小就是按鈕裏文本的大小。這個按鈕不需要指定 android:id 的屬性,因為 Activity 代碼中不會引用該 Button。
當前 EditText 和 Button 部件只是適應了他們各自內容的大小,如圖 2 所示:
圖 2 EditText 和 Button 窗體小組件使用 "wrap_content"
作為寬度屬性的值。
這樣設置對按鈕來說很合適,但是對於文本框來說就不太好了,因為用戶可能輸入更長的文本內容。因此如果能夠占滿整個屏幕寬度會更好。LinearLayout 使用 權重 屬性達到這個目,即 android:layout_weight 屬性。
權重的值指的是每個部件所占剩余空間的大小,該值與同級部件所占空間大小有關。這就類似於飲料的成分配方:“兩份伏特加酒,一份咖啡利口酒”,即該酒中伏特加酒占三分之二。例如,我們定義一個權重為 2 的 View,另一個 View 的權重是 1,那麽總數就是 3;這時第一個 View 占據 2/3 的空間,第二個占據 1/3 的空間。如果再加入第三個 View,權重設為 1,那麽第一個 View(權重為 2 的)會占據 1/2 的空間,剩余的另外兩個 View 各占 1/4。(請註意,使用權重的前提一般是給 View 的寬或者高的大小設置為 0dp,然後系統根據上面的權重規則來計算 View 應該占據的空間。但在很多情況下,如果給 View 設置了 match_parent 的屬性,那麽在計算權重時則不是通常的正比,而是反比。也就是說,權重值大的反而占據空間小)。
對於所有的 View 默認的權重是 0,如果只設置了一個 View 的權重大於 0,則該 View 將占據除去別的 View 本身占據的空間的所有剩余空間。因此這裏設置 EditText 的權重為 1,使其能夠占據除了按鈕之外的所有空間。
讓輸入框充滿整個屏幕的寬度
為讓 EditText 充滿剩余空間,做如下操作:
-
在
content_my.xml
文件裏,設置 [<EditText>] 的layout_weight
屬性值為1
。 -
設置 [<EditText>] 的
layout_width
值為0dp
。
res/layout/content_my.xml
<EditText
android:layout_weight="1"
android:layout_width="0dp"
... />
為了提升布局的效率,在設置權重時,應該把 EditText 的寬度設為 0dp。如果設置寬度為 "wrap_content"
,系統需要計算這個部件所占用的寬度;而此時的 EditText 因為設置了權重,所以會占據剩余空間;所以,最終導致的結果是:EditText 的寬度成了不起作用的屬性。
設置 EditText 權重後的效果如圖 3:
圖 3 因 EditText 窗體小組件被設置了全部權重,所以占據了 LinearLayout 的剩余空間。
現在看一下完整的布局文件內容:
res/layout/content_my.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_my">
<EditText android:id="@+id/edit_message"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send" />
</LinearLayout>
運行應用
整個布局默認被應用於創建項目的時候 SDK 工具自動生成的 Activity,運行看下效果:
-
在 Android Studio 裏,點擊工具欄裏的 Run 按鈕 。
-
或者使用命令行,進入你項目的根目錄直接執行:
$ ant debug adb install -r app/build/outputs/apk/app-debug.apk
下一小節將學習有關如何對按鈕做出相應,同時讀取文本中的內容,啟動另外一個 Activity 等。
3) 十分鐘學會android--建立第一個APP,建立簡單的用戶界面