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. 自行練習
進行下列操作:
- 建立其他計算器應用程式 (例如烹飪的單位轉換器),將毫升單位換算成液體或奶油量、從克杯換算成杯杯或從杯杯開始,以此類推。您需要哪些欄位?