1. 事前準備
從一開始,Jetpack Compose 的設計就包含與 View 的互通性,也就是讓 Compose 和 View 系統可以共用資源並搭配運作來顯示 UI。這項功能可讓您將 Compose 新增至以 View 為基礎的現有應用程式。這表示 Compose 和 View 可在程式碼集中並存,直到整個應用程式完全使用 Compose 為止。
在本程式碼研究室中,您會將 Juice Tracker 應用程式中以 View 為基礎的清單項目變更為 Compose。您可以視需要自行轉換 Juice Tracker 的其餘檢視區塊。
如果應用程式使用的是以 View 為基礎的 UI,您可能不想一次重寫整個 UI。本程式碼研究室會協助您在以 View 為基礎的 UI 中,將單ㄧ檢視區塊轉換為 Compose 元素。
必要條件
- 熟悉以 View 為基礎的 UI。
- 瞭解如何使用以 View 為基礎的 UI 建構應用程式。
- 具備 Kotlin 語法經驗 (包括 lambda)。
- 瞭解如何在 Jetpack Compose 中建構應用程式。
課程內容
- 如何將 Compose 新增至使用 Android View 建構的現有畫面。
- 將可組合函式新增至以 View 為基礎的應用程式後,如何進行預覽。
建構項目
- 在 Juice Tracker 應用程式中,將以 View 為基礎的清單項目轉換為 Compose。
2. 範例應用程式總覽
本程式碼研究室使用的範例程式碼為「使用 View 建構 Android 應用程式」中,Juice Tracker 應用程式的解決方案程式碼。此範例應用程式已使用 Room 持續性資料庫儲存資料。使用者可以在應用程式資料庫中新增果汁資訊,例如果汁名稱、說明、顏色和評等。
在本程式碼研究室中,您會將處於 View 狀態的清單項目轉換為 Compose。
下載本程式碼研究室的範例程式碼
如要開始使用,請先下載範例程式碼:
或者,您也可以複製 GitHub 存放區的程式碼:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views
您可以瀏覽 JuiceTracker
GitHub 存放區中的程式碼。
3. 新增 Jetpack Compose 程式庫
提醒您,Compose 和 View 可以並存在特定畫面中。您可以採用部分 Compose UI 元素,其他則採用 View 系統 UI 元素。舉例來說,您可以只採用 Compose 的清單,畫面的其餘部分則採用 View 系統。
如要將 Compose 程式庫新增至 Juice Tracker 應用程式,請完成下列步驟。
- 在 Android Studio 中開啟 Juice Tracker。
- 開啟應用程式層級的
build.gradle.kts
檔案。 - 在
buildFeatures
區塊內新增compose = true
標記。
buildFeatures {
//...
// Enable Jetpack Compose for this module
compose = true
}
這個標記可讓 Android Studio 與 Compose 共同運作。您未在先前的程式碼研究室中執行過這個步驟,是因為當您建立新的 Android Studio Compose 範本專案時,Android Studio 會自動產生這段程式碼。
- 在
buildFeatures
下方新增composeOptions
區塊。 - 在此區塊中,將
kotlinCompilerExtensionVersion
設為"1.5.1"
,設定 Kotlin 編譯器版本。
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
- 在
dependencies
區段中新增 Compose 依附元件。您需要具備下列依附元件,才能將 Compose 新增至以 View 為基礎的應用程式。這些依附元件可協助整合 Compose 與 Activity、新增 Compose 設計元件庫、支援 Compose Jetpack 主題設定,並提供改善 IDE 支援功能的工具。
dependencies {
implementation(platform("androidx.compose:compose-bom:2023.06.01"))
// other dependencies
// Compose
implementation("androidx.activity:activity-compose:1.7.2")
implementation("androidx.compose.material3:material3")
implementation("com.google.accompanist:accompanist-themeadapter-material3:0.28.0")
debugImplementation("androidx.compose.ui:ui-tooling")
}
新增 ComposeView
ComposeView
是可代管 Jetpack Compose UI 內容的 Android View。請使用 setContent
為 View 提供內容可組合函式。
- 開啟
layout/list_item.xml
並在「Split」分頁中查看預覽畫面。
完成本程式碼實驗室後,這個 View 會替換成可組合函式。
- 在
JuiceListAdapter.kt
所有位置移除ListItemBinding
。在JuiceListViewHolder
類別中,將binding.root
替換為composeView
。
import androidx.compose.ui.platform.ComposeView
class JuiceListViewHolder(
private val onEdit: (Juice) -> Unit,
private val onDelete: (Juice) -> Unit
): RecyclerView.ViewHolder(composeView)
- 在
onCreateViewHolder()
資料夾中,根據下列程式碼更新return()
函式:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JuiceListViewHolder {
return JuiceListViewHolder(
ComposeView(parent.context),
onEdit,
onDelete
)
}
- 在
JuiceListViewHolder
類別中,刪除所有private
變數,並從bind()
函式中移除所有程式碼。JuiceListViewHolder
類別現在會如以下程式碼所示:
class JuiceListViewHolder(
private val onEdit: (Juice) -> Unit,
private val onDelete: (Juice) -> Unit
) : RecyclerView.ViewHolder(composeView) {
fun bind(juice: Juice) {
}
}
- 此時,您可以刪除
com.example.juicetracker.databinding.ListItemBinding
和android.view.LayoutInflater
匯入內容。
// Delete
import com.example.juicetracker.databinding.ListItemBinding
import android.view.LayoutInflater
- 刪除
layout/list_item.xml
檔案。 - 在「Delete」對話方塊中選取「OK」。
4. 新增可組合函式
接下來,您會建立一個用來發送清單項目的可組合函式。這個可組合函式使用 Juice
和兩個回呼函式來編輯及刪除清單項目。
- 在
JuiceListAdapter.kt
中的JuiceListAdapter
類別定義之後,建立名為ListItem()
的可組合函式。 - 讓
ListItem()
函式接受Juice
物件,以及用於刪除的 lambda 回呼。
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun ListItem(
input: Juice,
onDelete: (Juice) -> Unit,
modifier: Modifier = Modifier
) {
}
請查看要建立的清單項目預覽畫面。請注意,預覽畫面包含果汁圖示、果汁詳細資料和刪除按鈕圖示。您即將實作這些元件。
建立果汁圖示可組合項
- 在
JuiceListAdapter.kt
中的ListItem()
可組合函式之後,建立另一個名為JuiceIcon()
的可組合函式,並採用color
和Modifier
。
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
}
- 在
JuiceIcon()
函式中,為color
和內容說明新增變數,如以下程式碼所示:
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
val colorLabelMap = JuiceColor.values().associateBy { stringResource(it.label) }
val selectedColor = colorLabelMap[color]?.let { Color(it.color) }
val juiceIconContentDescription = stringResource(R.string.juice_color, color)
}
您可以使用 colorLabelMap
和 selectedColor
變數,擷取與使用者選取項目相關聯的顏色資源。
- 新增
Box
版面配置,讓兩個圖示ic_juice_color
和ic_juice_clear
彼此重疊顯示。ic_juice_color
圖示已上色,且置中對齊。
import androidx.compose.foundation.layout.Box
Box(
modifier.semantics {
contentDescription = juiceIconContentDescription
}
) {
Icon(
painter = painterResource(R.drawable.ic_juice_color),
contentDescription = null,
tint = selectedColor ?: Color.Red,
modifier = Modifier.align(Alignment.Center)
)
Icon(painter = painterResource(R.drawable.ic_juice_clear), contentDescription = null)
}
由於您已熟悉可組合函式的實作方式,這裡就不再詳細說明。
- 新增用來預覽
JuiceIcon()
的函式,並傳遞顏色為Yellow
。
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
fun PreviewJuiceIcon() {
JuiceIcon("Yellow")
}
建立果汁詳細資料可組合函式
在 JuiceListAdapter.kt
中,您需要新增其他可組合函式來顯示果汁詳細資料。此外,還需要 Column 版面配置,用來顯示名稱和說明的兩個 Text
可組合函式,以及評等指標。若要這樣做,請完成下列步驟:
- 新增名為
JuiceDetails()
的可組合函式,該函式會採用Juice
物件和Modifier
,以及分別用於果汁名稱和說明的兩個可組合函式,如以下程式碼所示:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.text.font.FontWeight
@Composable
fun JuiceDetails(juice: Juice, modifier: Modifier = Modifier) {
Column(modifier, verticalArrangement = Arrangement.Top) {
Text(
text = juice.name,
style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold),
)
Text(juice.description)
RatingDisplay(rating = juice.rating, modifier = Modifier.padding(top = 8.dp))
}
}
- 如要排解未解決的參照錯誤,請建立名為
RatingDisplay()
的可組合函式。
在 View 系統中,您可以使用 RatingBar
顯示以下評等列。Compose 沒有評等列可組合函式,因此您需要從頭開始實作這項元素。
- 定義
RatingDisplay()
函式,依照評等顯示星號。這個可組合函式會根據評等顯示星號數量。
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
@Composable
fun RatingDisplay(rating: Int, modifier: Modifier = Modifier) {
val displayDescription = pluralStringResource(R.plurals.number_of_stars, count = rating)
Row(
// Content description is added here to support accessibility
modifier.semantics {
contentDescription = displayDescription
}
) {
repeat(rating) {
// Star [contentDescription] is null as the image is for illustrative purpose
Image(
modifier = Modifier.size(32.dp),
painter = painterResource(R.drawable.star),
contentDescription = null
)
}
}
}
如要在 Compose 中建立星型可繪項目,您需要建立星型向量素材資源。
- 在「Project」窗格的「drawable」上按一下滑鼠右鍵,依序點選「New」>「Vector Asset」。
- 在「Asset Studio」對話方塊中搜尋星號圖示,選取實心星號圖示。
- 將星號的顏色值變更為 625B71。
- 依序點選「Next」>「Finish」。
- 請注意,可繪項目會顯示在
res/drawable
資料夾中。
- 新增預覽可組合函式,用來預覽
JuiceDetails
可組合函式。
@Preview
@Composable
fun PreviewJuiceDetails() {
JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}
建立 DeleteButton 可組合函式
- 在
JuiceListAdapter.kt
中,新增另一個名為DeleteButton()
的可組合函式,該函式會採用 lambda 回呼函式和修飾符。 - 將 lambda 設為
onClick
引數並傳入Icon()
,如以下程式碼所示:
import androidx.compose.ui.res.painterResource
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@Composable
fun DeleteButton(onDelete: () -> Unit, modifier: Modifier = Modifier) {
IconButton(
onClick = { onDelete() },
modifier = modifier
) {
Icon(
painter = painterResource(R.drawable.ic_delete),
contentDescription = stringResource(R.string.delete)
)
}
}
- 新增預覽函式,用來預覽刪除按鈕。
@Preview
@Composable
fun PreviewDeleteIcon() {
DeleteButton({})
}
5. 實作 ListItem 函式
現在,您已擁有顯示清單項目的所有必要可組合函式,可以在版面配置中排列這些項目了。請留意您在先前步驟中定義的 ListItem()
函式。
@Composable
fun ListItem(
input: Juice,
onEdit: (Juice) -> Unit,
onDelete: (Juice) -> Unit,
modifier: Modifier = Modifier
) {
}
在 JuiceListAdapter.kt
中,完成下列步驟來實作 ListItem()
函式。
- 在
Mdc3Theme {}
lambda 中加入Row
版面配置。
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import com.google.accompanist.themeadapter.material3.Mdc3Theme
Mdc3Theme {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween
) {
}
}
- 在
Row
lambda 中,呼叫建立為子項元素的三個可組合函式JuiceIcon
、JuiceDetails
和DeleteButton
。
JuiceIcon(input.color)
JuiceDetails(input, Modifier.weight(1f))
DeleteButton({})
將 Modifier.
weight
(1f)
傳遞至 JuiceDetails()
可組合函式,確保在測量未加權的子項元素後,果汁詳細資料會佔用剩餘的水平空間。
- 將
onDelete(input)
lambda 和靠上對齊修飾符做為參數,傳入至DeleteButton
可組合函式。
DeleteButton(
onDelete = {
onDelete(input)
},
modifier = Modifier.align(Alignment.Top)
)
- 編寫預覽函式,用來預覽
ListItem
可組合函式。
@Preview
@Composable
fun PreviewListItem() {
ListItem(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4), {})
}
- 將
ListItem
可組合函式繫結至 View Holder。在clickable()
lambda 函式中呼叫onEdit(input)
,即可在使用者點選該清單項目時,開啟編輯對話方塊。
在 JuiceListViewHolder
類別的 bind()
函式中,您需要代管可組合函式。請使用 ComposeView
,這種 Android View 能使用其 setContent
方法代管 Compose UI 內容。
fun bind(input: Juice) {
composeView.setContent {
ListItem(
input,
onDelete,
modifier = Modifier
.fillMaxWidth()
.clickable {
onEdit(input)
}
.padding(vertical = 8.dp, horizontal = 16.dp),
)
}
}
- 執行應用程式。新增您喜歡的果汁。請欣賞您製作的全新 Compose 清單項目。
恭喜!您剛剛建立了第一個具有 Compose 互通性的應用程式,也就是在以 View 為基礎的應用程式中使用 Compose 元素的應用程式。
6. 取得解決方案程式碼
完成程式碼研究室後,如要下載當中用到的程式碼,您可以使用這些 git 指令:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views-with-compose
另外,您也可以下載存放區為 ZIP 檔案,然後解壓縮並在 Android Studio 中開啟。
如要查看解決方案程式碼,請前往 GitHub。
7. 瞭解詳情
Android 開發人員說明文件
- Compose 專用工具 | Jetpack Compose | Android 開發人員
- 互通性 API | Jetpack Compose | Android 開發人員
- 遷移策略 | Jetpack Compose | Android 開發人員
程式碼研究室 [中級]