1. 事前準備
在本程式碼研究室中,您將為基本的小費計算機應用程式建構版面配置。在程式碼研究室結束時,應用程式的使用者介面已可運作,但還不會實際計算小費。以下程式碼研究室將說明如何讓應用程式正常運作且表現更專業。
必要條件
- 可透過 Android Studio 中的範本建立及執行 Android 應用程式
課程內容
- 如何在 Android 中讀取及寫入 XML 版面配置
- 如何建構簡易表單,用於使用者文字輸入和選項
建構項目
- 小費計算機 Android 應用程式適用的使用者介面
需求條件
- 電腦已安裝最新版 Android Studio
- 網際網路連線,以存取 Android 開發人員說明文件
2. 啟動專案
使用 Google 提供的小費計算機:https://www.google.com/search?q=tip+calculator

在這個途徑中,您應該使用 Android 應用程式建立簡易的計算機簡易版。
開發人員通常就是採用這樣的做法作業:取得簡易版本的應用程式,並讓應用程式正常運作 (即使看起來不太好),之後仍能流暢地使用這些功能和影視內容。
完成程式碼研究室後,您的小費計算機應用程式會如下所示:

您需要使用 Android 提供的下列 UI 元素:
EditText- 用於輸入及傳送訊息TextView- 顯示服務條款和小費金額等文字RadioButton:每個小費選項的可選取圓形按鈕RadioGroup- 將圓形按鈕選項分組Switch- 開啟/關閉切換按鈕,選擇是否將小費四捨五入
建立一個空白活動專案
- 首先,在 Android Studio 中使用 空白活動 範本來建立新品的 Kotlin 專案。
- 呼叫應用程式「提示時間」,最低 API 級別為 19 (KitKat)。套件名稱為 com.example.tiptime。

- 按一下「Finish」即可建立應用程式。
3. 讀取及瞭解 XML
如果不想使用自己熟悉的版面配置編輯器,您可以修改描述使用者介面的 XML 來建構應用程式的版面配置。瞭解使用 XML 瞭解及修改 UI 版面配置對 Android 開發人員的重要性。
您將會查看並編輯 XML 檔案,為這個應用程式定義 UI 版面配置。XML 是可延伸標記語言的一種,這是一種利用文字文件來描述資料的方式。由於 XML 是可擴充且極具彈性的功能,所以有許多種不同的用途,包括定義 Android 應用程式的 UI 版面配置。您或許可以在先前的程式碼研究室中回想起,「strings.xml」這個 XML 檔案中的其他資源也定義了其他資源。
Android 應用程式的使用者介面是由元件(小工具)的元件階層組成,以及這些元件的螢幕版面配置。請注意,這些版面配置本身是 UI 元件。
您必須說明畫面上的 UI 元素檢視畫面階層。舉例來說,ConstraintLayout (父項) 可包含 Buttons、TextViews、ImageViews 或其他檢視畫面 (子項)。請注意,ConstraintLayout 是 ViewGroup 的子類別。可讓您靈活設定子項的位置或調整大小。

Android 應用程式的內含項目階層

每個 UI 元素都會在 XML 檔案中以 XML 元素出現。每個元素的開頭和結尾都是代碼,而每個標記的開頭都是 <,結尾則是 >。就像您可以使用版面配置編輯器 (設計) 設定 UI 元素的屬性,XML 元素也可以具有「屬性」。簡單來說,上述 UI 元素的 XML 可能如下所示:
<ConstraintLayout>
<TextView
text="Hello World!">
</TextView>
</ConstraintLayout>

以下是一個實際範例。
- 開啟
activity_main.xml(「app」>「res」>「layout」>「activity_main.xml」) - 您可能會注意到應用程式顯示包含「Hello World!」的
TextView。如ConstraintLayout中所述,您在使用這個範本建立的先前的專案中看過。

- 在版面配置編輯器的右上方,找到「Code」、「Split」和「Design」檢視畫面的選項。
- 選取「Code」檢視。

activity_main.xml 中的 XML 如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
其中有簡單的說明比簡單的範例來得好,但 Android Studio 有一些努力能讓 XML 更易於閱讀,就像使用 Kotlin 程式碼一樣。
- 請注意縮排。Android Studio 會自動執行上述作業,顯示元素階層。
TextView已縮排,因為ConstraintLayout裡包含這個項目。ConstraintLayout是父項,TextView是子節點。每個元素的屬性會以縮排的方式顯示,表示該元素屬於該元素的一部分。 - 請注意色彩編碼:有些項目是藍色,部分是綠色,依此類推。檔案的類似部分會繪製成同一顏色,方便您比對。請特別注意,Android Studio 會繪製用相同顏色元素的開始和結尾。(注意:程式碼研究室所用的顏色可能會與 Android Studio 中顯示的顏色不符)。
XML 標記、元素和屬性
以下是 TextView 元素的簡化版本,方便您查看部分重要部分:
<TextView
android:text="Hello World!"
/>
包含 <TextView 的行則是標記的開頭,而 /> 行則是標記結尾。標有 android:text="Hello World!" 的行是標記的屬性。這代表 TextView 將要顯示的文字。這 3 行是常用的簡寫,又稱為「空白元素標記」。也就是說,如果您利用獨立的「start-tag」和「end-tag」編寫程式碼,例如:
<TextView
android:text="Hello World!"
></TextView>
另一個常見的例子是空白元素標記,編寫時盡可能減少這類標記的行數,然後將代碼的結尾與行前的行結合。因此,您可能會在兩行中看到空白元素標記 (沒有屬性的話,甚至只有一行):
<!-- with attributes, two lines -->
<TextView
android:text="Hello World!" />
由於 ConstraintLayout 元素是以獨立開始和結束標記寫成,因此必須含有其他元素。以下是含有 TextView 元素的 ConstraintLayout 元素簡化版本:
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
</androidx.constraintlayout.widget.ConstraintLayout>
如要將另一個 View 新增為 ConstraintLayout 的子項 (例如 TextView 下的 Button),其會在 TextView 標記 /> 的結尾,並且在 ConstraintLayout 的結尾標記之前,如下所示:
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
<Button
android:text="Calculate" />
</androidx.constraintlayout.widget.ConstraintLayout>
進一步瞭解版面配置的 XML
- 查看
ConstraintLayout的標記,您會發現這顯示為androidx.constraintlayout.widget.ConstraintLayout,而非和TextView一樣只有ConstraintLayout。這是因為ConstraintLayout是 Android Jetpack 的一部分,而其中的程式碼程式庫在 Android 核心平台之外提供了額外功能。Jetpack 提供了一些實用功能,可協助您輕鬆建構應用程式。您會發現此 UI 元件因為是以「androidx」開頭,所以屬於 Jetpack 的一部分。 - 您可能會發現開頭為
xmlns:的行數,後接android、app和tools。
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"
xmlns 代表 XML 命名空間,而每一行分別定義一個「結構定義」或相關詞彙。舉例來說,android: 命名空間會標示 Android 系統定義的屬性。版面配置 XML 中的所有屬性都是從其中一個命名空間開始執行。
- XML 元素之間的空白字元不會對電腦產生意義,但可讓 XML 更易於閱讀。
Android Studio 會自動加入一些空白字元和縮排,為了方便閱讀。在稍後說明,我們會說明如何讓 Android Studio 確保您的 XML 採用程式碼樣式慣例。
- 您可以對 XML 新增註解,就跟使用 Kotlin 程式碼一樣。開頭是
<!--,結尾是-->。
<!-- this is a comment in XML -->
<!-- this is a
multi-line
Comment.
And another
Multi-line comment -->
- 請注意檔案的第一行:
<?xml version="1.0" encoding="utf-8"?>
用於表示檔案是 XML 檔案,但並非所有 XML 檔案都會包含這類檔案。
4. 在 XML 中製作版面配置
- 在
activity_main.xml中,請切換至「Split」 畫面,即可查看 設計編輯器 旁的 XML。「設計編輯器」可讓您預覽 UI 版面配置。

- 您可以自行決定要使用哪個方式檢視,但是在這個程式碼研究室中,請使用「Split」檢視,這樣您才可以同時查看您編輯的 XML,以及在「Design Editor」中編輯所帶來的變更。
- 請嘗試點選其他行 (
ConstraintLayout下和TextView下一行),然後可注意到會選取到「Design Editor」中對應的畫面。反之亦然。舉例來說,如果您在「Design Editor」中按一下TextView,系統就會醒目顯示對應的 XML。

刪除 TextView
- 您現在不需要
TextView,請將其刪除。請務必從<TextView至/>結尾全部刪除。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
檔案還剩 ConstraintLayout:
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
- 在
ConstraintLayout中加入 16dp 邊框間距,避免 UI 與螢幕邊緣過度擁擠。
邊框間距與邊界相似,但會在 ConstraintLayout 內部增加空格,而不是在外部增加空格。
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
新增服務費用文字欄位
在這個步驟中,您必須新增 UI 元素,才能在應用程式中輸入服務費用。您必須使用 EditText 元素,讓使用者在應用程式中輸入或修改文字。

- 請參閱
EditText說明文件,並檢視 XML 範例。 - 找出
ConstraintLayout開頭和結尾標記之間的空白區塊。 - 將說明文件中的 XML 複製並貼到 Android Studio 的版面配置中。
您的版面配置檔案應該會如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="text"/>
</androidx.constraintlayout.widget.ConstraintLayout>
目前您可能不清楚,但會在下列步驟中進一步說明。
- 請注意,
EditText會加上紅色底線。 - 將滑鼠游標移到指標上,系統就會顯示「檢視畫面不受限」的錯誤訊息,您對在舊版程式碼研究室中的這類程式碼應該十分熟悉。先前提過,
ConstraintLayout的子項設有限制,因此版面配置會熟悉該如何排列。

- 將這些限制新增至
EditText可固定在父項的左上角。
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
如果使用英文或其他由左至右的語言 (LTR),則起始點在左側。不過,部分語言 (例如阿拉伯字母) 的書寫順序是由右至左 (RTL),因此開頭應在右側。因此,該限制使用「start」,以便與 LTR 或 RTL 語言搭配使用。同樣地,限制都會使用「end」而不是右方。
加入新限制條件後,EditText 元素會如下所示:
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="text"/>
查看編輯文字屬性
請仔細檢查您貼上的所有 EditText 屬性,確保它們與您應用程式中的方式搭配運作。
- 找出設為
@+id/plain_text_input的id屬性。 - 將
id屬性變更為較為適當的名稱@+id/cost_of_service。
- 查看
layout_height屬性。已設為wrap_content,表示高度會和當中的內容高度相同。沒關係,因為只有 1 行文字。 - 查看
layout_width屬性。已設為match_parent,但你無法在ConstraintLayout的子項中設定match_parent。此外,文字欄位不需要那麼寬。設為160dp的固定寬度,但應預留足夠空間,讓使用者輸入服務費用。

- 找到新的
inputType屬性,這是一項新功能。屬性值為"text",表示使用者可在畫面上的欄位中輸入任何文字字元 (英數字元、符號等)。
android:inputType="text"
不過,假如您只想在 EditText 中輸入數字,因為該欄位代表貨幣金額。
- 清除
text字詞,但保留引號。 - 輸入
number的位置。輸入「n」後,Android Studio 會顯示包含「n」的可能完成項目清單。

- 選擇
numberDecimal,這個類型可限制只顯示含小數點的數字。
android:inputType="numberDecimal"
如要查看輸入類型的其他選項,請參閱開發人員說明文件中的 指定輸入法類型。
因此,建議您再做些修改,因為這能夠在使用者輸入欄位中的提示內容,所以很實用。
- 在
EditText中加入hint屬性,藉此說明使用者應在欄位中輸入的內容。
android:hint="Cost of Service"
您也會看到「Design Editor」將其更新。

- 在模擬器中執行應用程式。看起來應該像這樣:

做得好!這項服務尚未處理完成,但您已經有良好的第一步,並編輯了部分 XML。版面配置的 XML 應如下所示。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="Cost of Service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
新增服務問題
在這個步驟中,您必須新增 TextView 問題說明:“服務如何?“請嘗試輸入,不要複製/貼上。你可以透過 Android Studio 提供建議的做法。
- 關閉
EditText標記/>後,新增一行然後開始輸入<TextView - 從建議中選取
TextView,Android Studio 就會自動為TextView新增layout_width和layout_height屬性。 - 請為這兩個屬性選擇
wrap_content,因為TextView只需要與當中的文字內容一樣大。
- 新增含有
"How was the service?"的text屬性
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
- 使用
/>關閉標記。 - 請注意,在「Design Editor」中
TextView會與EditText重疊。

這樣看起來並不正確,因此請在接下來的 TextView 中加入限制。想想您需要哪些限制。TextView 應水平和垂直放置在哪些位置?您可參考下方的應用程式螢幕截圖瞭解適當的位置。

就垂直位置來說,TextView 應低於服務費用文字欄位。水平指定您要讓 TextView 對齊父項的邊緣。
- 為
TextView加上水平限制,限制它的起點到父項的起點。
app:layout_constraintStart_toStartOf="parent"
- 在
TextView中加入垂直限制,將TextView的上緣限制在服務費用View的底部邊緣。
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
請注意,@id/cost_of_service 中沒有加號,因為 ID 已定義。

這個部分還目前為止看起來還不夠好,但不用擔心。我們要確保所有必要畫面都顯示在這裡,且功能可以正常運作。您將在下列程式碼研究室中修正這個問題。
- 在
TextView新增資源 ID。您稍後必須參考這個資料檢視,因為我們建議您新增更多檢視點,並將這些項目互相衝突。
android:id="@+id/service_question"
此時,您的 XML 應如下所示。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"/>
</androidx.constraintlayout.widget.ConstraintLayout>
5. 新增提示選項
接下來,您需要為各個使用者選項提供圓形按鈕選項。
共有三個選項:
- 極佳 (20%)
- 不錯 (18%)
- 一般 (15%)
如果您不確定該如何操作,可以使用 Google 搜尋。這是開發人員在卡車時會用到的工具。
- 在 Google 上搜尋「
radio button android」。最理想的搜尋結果為 Android 開發人員網站提供的指南,瞭解如何使用圓形按鈕。

- 瀏覽圓形按鈕指南。
閱讀說明後,您可以確認可在自己的版面配置中,針對每個所需的圓形按鈕使用 RadioButton UI 元件。此外,您還必須在 RadioGroup 中將圓形按鈕分組,因為一次只能選取一個選項。
部分 XML 似乎符合您的需求。仔細閱讀,瞭解 RadioGroup 是父項檢視,以及 RadioButtons 的子項檢視。
- 返回 Android Studio 中的版面配置,將
RadioGroup和RadioButton新增至應用程式。 - 在
TextView元素之後,仍顯示在ConstraintLayout中,開始輸入<RadioGroup。Android Studio 會提供實用的建議來協助您完成 XML。
- 將
RadioGroup的layout_width和layout_height設為wrap_content。 - 新增設為
@+id/tip_options的資源 ID。 - 使用
>關閉起始標記。 - Android Studio 會加上
</RadioGroup>。和ConstraintLayout一樣,RadioGroup元素內部也會包含其他元素,因此建議您將元素移到單獨的線條。
- 將
RadioGroup限制在服務問題下方 (垂直),並限制父項的開頭 (水平)。 - 將
android:orientation屬性設為vertical。如要指定某列的RadioButtons,可以將方向設為horizontal。
RadioGroup 的 XML 應如下所示:
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
</RadioGroup>
新增圓形按鈕
- 在
RadioGroup的最後一個屬性後方,在</RadioGroup>結束標記之前加上RadioButton。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<!-- add RadioButtons here -->
</RadioGroup>
- 將
layout_width和layout_height設為wrap_content。 - 將
@+id/option_twenty_percent的資源 ID 指派給RadioButton。 - 將文字設為
Amazing (20%)。 - 使用
/>關閉標記。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
</RadioGroup>

您已新增一個 RadioButton,是否可以修改 XML,為 Good (18%) 和 Okay (15%) 選項新增 2 個圓形按鈕?
以下是 RadioGroup 和 RadioButtons 的 XML 外觀:
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>

新增預設選項
目前未選取任何提示選項。系統預設會選取其中一個圓形按鈕選項。
RadioGroup 上有一個屬性可讓您指定要先檢查哪一個按鈕。名稱是 checkedButton,並設為所選圓形按鈕的按鈕資源
- 在
RadioGroup上,將android:checkedButton屬性設為@id/option_twenty_percent。
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
...
請注意到「Design Editor」中的版面配置已更新。根據預設,系統會選取 20% 的小費選項!現在這開始看起來像小費計算機了!

XML 目前看起來會像這樣:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
6. 完成版面配置的其餘部分
您現在已進入版面配置的最後一個部分。請新增 Switch、Button 和 TextView 以顯示小費金額。

新增切換鈕,讓小費四捨五入
接下來,您將使用 Switch 小工具,讓使用者選取「Yes」或「No」是否要將小費四捨五入。
您想要 Switch 的寬度和父項一樣,因此您可能會認為寬度應該設為 match_parent。如前文所述,您無法在 ConstraintLayout 的 UI 元素上設定 match_parent。相反地,您需要限制檢視畫面的開始和結束時間,並將寬度設為 0dp。將寬度設為 0dp 可讓系統不要計算寬度,只要嘗試與檢視畫面中的限制條件相符即可。
- 在
RadioGroup的 XML 後方加入Switch元素。 - 如上所述,將
layout_width設為0dp - 將
layout_height設為wrap_content這會將Switch觀看內容與內部內容高度一樣。 - 將
id屬性設為@+id/round_up_switch。 - 將
text屬性設為Round up tip?。這會做為Switch的標籤使用。 - 將
Switch的起始點限制為tip_options的起始邊緣,並將結尾點限制為父項的終點邊緣。 - 將
Switch的頂端限制在tip_options的底部。 - 使用
/>關閉標記。
如果切換按鈕預設為開啟,且有 android:checked 的屬性,則可能的值為 true (開啟) 或 false (關閉)。
- 將
android:checked屬性設為true。
總而言之,Switch 元素的 XML 看起來會像這樣:
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="Round up tip?"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />

新增計算按鈕
接著,您必須新增 Button 來向使用者說明小費的計算方式。您想將按鈕設為與上層最寬,因此水平限制和寬度與 Switch 相同。
- 在
Switch後方加上Button。 - 請將寬度設為
0dp,方法與Switch相同。 - 將高度設為
wrap_content。 - 為資源 ID
@+id/calculate_button輸入文字,格式為「"Calculate"」。 - 將
Button的上方邊緣固定到 圓頭提示的底部邊緣?Switch. - 將起始邊緣限制為上層的起點,以及將結尾邊緣設為父項的終點邊緣。
- 使用
/>關閉標記。
以下是「Calculate」Button 的 XML 內容:
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Calculate"
app:layout_constraintTop_toBottomOf="@id/round_up_switch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

新增小費計算結果
就快完成了版面配置!在這個步驟中,您會為小費的結果加上 TextView、將其放在「Calculate」按鈕下方,並且與結尾處對齊,而非與其他 UI 元素一樣放在開始處。
- 新增具有 ID 為
tip_result且 ID 為Tip Amount的TextView。 - 將
TextView的結尾邊緣限制在父項的終點邊緣。 - 限制「Calculate」按鈕的上方與下方的邊緣。
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button"
android:text="Tip Amount" />

- 執行應用程式。看起來應該要像這個螢幕截圖一樣。

真厲害,如果您是第一次使用 XML 的話,那真是太棒了!
請注意,應用程式範本可能會與螢幕截圖有所不同,這是因為範本可能會在後續的 Android Studio 版本中有所變更。「Calculate」按鈕目前還沒有任何作用,但您可以輸入費用、選取小費百分比,然後切換是否要將小費四捨五入。在下一個程式碼研究室中您將會讓「Calculate」按鈕正常運作,所以請務必回來查看!
7. 採用好的程式設計做法
擷取字串
您可能會注意到有關硬式編碼字串的警告。請回顧先前的程式碼研究室,瞭解如何將字串擷取到資源檔案,以便更輕鬆地將應用程式翻譯成其他語言,並重複使用字串。瀏覽 activity_main.xml 並擷取所有字串資源。
- 按一下字串;將滑鼠游標懸停在顯示的黃色燈泡圖示上,然後按一下旁邊的三角形圖示;選擇「Extract String Resource」。字串資源的預設名稱沒有問題。您可以視需要根據提示選擇使用
amazing_service、good_service和ok_service,讓名稱更加描述性。
現在請驗證剛新增的字串資源。
- 如果畫面上未顯示「Project」視窗,請按一下視窗左側的「Project」分頁標籤。
- 開啟 app > res > values > string.xml 查看所有 UI 字串資源。
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
重新格式化 XML
Android Studio 提供各式各樣的程式碼,可用於調整程式碼,確保程式碼符合建議的程式設計慣例。
- 在
activity_main.xml中,選擇「Edit」>「Select All」。 - 依序選擇「Code」>「Reformat Code」。
以確保縮排一致,且可能會將 UI 元素的部分 XML 重新排序,例如將單一元素的所有 android: 屬性放在一起。
8. 解決方案程式碼

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="@string/cost_of_service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/how_was_the_service"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service" />
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@id/option_twenty_percent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/amazing_service" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/good_service" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok_service" />
</RadioGroup>
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/round_up_tip"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/calculate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/round_up_switch" />
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tip_amount"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
res/values/strings.xml
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
9. 摘要
- XML (擴充標記語言) 可用來管理文字,由標記、元素和屬性構成。
- 使用 XML 定義 Android 應用程式的版面配置。
- 使用
EditText可讓使用者輸入內容或編輯文字。 EditText可提示用戶指定該欄位的內容。- 指定
android:inputType屬性,以限制用戶可輸入EditText欄位的文字類型。 - 列出包含
RadioButtons的獨家選項清單 (使用RadioGroup分組)。 RadioGroup可以是垂直或水平,而您也可以指定要最初選取的RadioButton。- 使用
Switch可讓用戶在兩個選項之間切換。 - 您不必使用個別的
TextView,就可以將標籤新增至Switch。 ConstraintLayout中的每個子項都必須包含垂直和水平限制條件。- 使用「start」和「end」限制條件來處理由左至右 (LTR) 和右至左 (RTL) 的語言。
- 限制屬性名稱會依照
layout_constraint<Source>_to<Target>Of的格式提供。 - 如要讓
View盡可能適用於目標ConstraintLayout,請將開頭和結尾限制為父項的開頭和結尾,然後將寬度設為 0dp。
10. 瞭解詳情
以下提供涵蓋主題的更多說明文件連結。如要查看所有 Android 開發說明文件,請前往 developer.android.com。 別忘了,如果遇到困難,您可以執行 Google 搜尋。
11. 自行練習
進行下列操作:
- 建立其他計算器應用程式 (例如烹飪的單位轉換器),將毫升單位換算成液體或奶油量、從克杯換算成杯杯或從杯杯開始,以此類推。您需要哪些欄位?