1. 事前準備
最初設計 Jetpack Compose 的用意就是要與 View 互通,也就是讓 Compose 和 View 系統可以共用資源並搭配運作來顯示 UI。這項功能可讓您將 Compose 新增到以 View 為基礎的現有應用程式。這表示您的 Compose 和 View 可在程式碼集中並存,直到整個應用程式都使用 Compose 為止。
在本程式碼研究室中,您要將 Juice Tracker 應用程式中以 View 為基礎的清單項目變更為 Compose。您可以視需要自行轉換 Juice Tracker 的其餘檢視畫面。
如果應用程式使用的是以 View 為基礎的 UI,您可能不想一次重寫整個 UI。本程式碼研究室可協助您將以 View 為基礎的 UI 中的單個 View 轉換為 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 程式庫
Recollect、Compose 和 View 可以同時存在於特定畫面中。您可以在 Compose 中採用部分 UI 元素,並在 View 系統採用其他元素。舉例來說,您可以只將清單放在 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 與活動、新增 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)
如要解決這個錯誤,您需要從所有位置移除 ListItemBinding
。
- 在
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
中,您必須新增其他可組合函式來顯示果汁詳細資料。您還需要一個版面配置,用來顯示這兩個 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
資料夾中。
「drawable」資料夾" class="l10n-absolute-url-src" l10n-attrs-original-order="alt,title,style,src,srcset,sizes,class" l10n-encrypted-style="RGnmf9pBZ8wivd+Oe4aHdk8zz2uYoEmRhrQeP6/mnhY=" sizes="(max-width: 840px) 100vw, 856px" src="https://developer.android.com/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb.png" srcset="/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_36.png 36w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_48.png 48w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_72.png 72w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_96.png 96w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_480.png 480w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_720.png 720w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_856.png 856w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_960.png 960w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_1440.png 1440w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_1920.png 1920w,/static/codelabs/basic-android-kotlin-training-compose-add-compose-to-a-view-based-app/img/cbde1500b88bfeb_2880.png 2880w" style="width: 377.00px" title="新的可繪項目檔案名為 star.xml,位於 drawable 資料夾下方" />
- 新增預覽可組合項,用來預覽
JuiceDetails
可組合項。
@Preview
@Composable
fun PreviewJuiceDetails() {
JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}
建立「刪除」按鈕可組合函式
- 在
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 預留位置。當使用者點選該清單項目時,在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 開發人員
程式碼研究室 [中級]