將 Compose 新增到以 View 為基礎的應用程式

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 應用程式,請完成下列步驟。

  1. 在 Android Studio 中開啟 Juice Tracker。
  2. 開啟應用程式層級的 build.gradle.kts 檔案。
  3. buildFeatures 區塊內新增 compose = true 標記。
buildFeatures {
    //...
    // Enable Jetpack Compose for this module
    compose = true
}

這個標記可讓 Android Studio 與 Compose 搭配使用。您未在先前的程式碼研究室中完成這個步驟,這是因為當您建立新的 Android Studio Compose 範本專案時,Android Studio 會自動產生這個程式碼。

  1. buildFeatures 下方新增 composeOptions 區塊。
  2. 在區塊中,將 kotlinCompilerExtensionVersion 設為 "1.5.1",即可設定 Kotlin 編譯器版本。
composeOptions {
    kotlinCompilerExtensionVersion = "1.5.1"
}
  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 提供內容可組合函式。

  1. 開啟 layout/list_item.xml 並在「Split」分頁中查看預覽畫面。

完成本程式碼研究室之後,您將以可組合項取代這個 View。

f85c6002df3265e0.png

  1. 如要解決這個錯誤,請在 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

  1. onCreateViewHolder() 資料夾中,將 return() 函式更新為符合下列程式碼:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JuiceListViewHolder {
   return JuiceListViewHolder(
       ComposeView(parent.context),
       onEdit,
       onDelete
   )
}
  1. JuiceListViewHolder 類別中,刪除所有 private 變數,並移除 bind() 函式中的所有程式碼。您的 JuiceListViewHolder 類別現在會類似下列程式碼:
class JuiceListViewHolder(
    private val onEdit: (Juice) -> Unit,
    private val onDelete: (Juice) -> Unit
) : RecyclerView.ViewHolder(composeView) {

   fun bind(juice: Juice) {

   }
}
  1. 此時,您可以刪除 com.example.juicetracker.databinding.ListItemBindingandroid.view.LayoutInflater 匯入內容。
// Delete
import com.example.juicetracker.databinding.ListItemBinding
import android.view.LayoutInflater
  1. 刪除 layout/list_item.xml 檔案。
  2. 請在「Delete」對話方塊中選取「OK」

86dd7cba7e181e54.png

4. 新增可組合函式

接著,您會建立一個用來發送清單項目的可組合項。可組合項使用 Juice 及兩個回呼函式來編輯及刪除清單項目。

  1. JuiceListAdapter.kt 中的 JuiceListAdapter 類別定義之後,建立名為 ListItem() 的可組合函式。
  2. ListItem() 函式接受 Juice 物件,以及用於刪除的 lambda 回呼。
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

@Composable
fun ListItem(
    input: Juice,
    onDelete: (Juice) -> Unit,
    modifier: Modifier = Modifier
) {
}

請檢視您要建立的清單項目預覽畫面,並留意項目包含果汁圖示、果汁詳細資料和刪除按鈕圖示。您很快就會實作這些元件。

cf3b235dcb93e998.png

建立果汁圖示可組合項

  1. JuiceListAdapter.kt 中,在 ListItem() 可組合項之後,建立另一個名為 JuiceIcon() 的可組合函式,該函式使用 colorModifier
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {

}
  1. 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)

}

使用 colorLabelMapselectedColor 變數時,您可以擷取與使用者選取項目相關聯的顏色資源。

  1. 新增 Box 版面配置,重疊顯示 ic_juice_coloric_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)
}

由於您已熟悉可組合函式的實作方式,這裡就不再詳細說明。

  1. 新增用來預覽 JuiceIcon() 的函式。將顏色傳遞為 Yellow
import androidx.compose.ui.tooling.preview.Preview

@Preview
@Composable
fun PreviewJuiceIcon() {
    JuiceIcon("Yellow")
}

黃色果汁圖示的預覽畫面

建立果汁詳細資料可組合項

JuiceListAdapter.kt 中,您必須新增其他可組合函式來顯示果汁詳細資料。您還需要一個版面配置,用來顯示這兩個 Text 可組合函式的名稱和說明,以及評分指標。如要這樣做,請完成下列步驟:

  1. 新增名為 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))
   }
}
  1. 如要排解未解決的參照錯誤,請建立名為 RatingDisplay() 的可組合函式。

4018a1be2b3e7399.png

在 View 系統中,您可以使用 RatingBar 顯示以下評分列。Compose 沒有評分列可組合函式,因此您需要從頭開始實作這項元素。

  1. 定義 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 中建立星型可繪項目,您需要建立星型向量素材資源。

  1. 在「Project」窗格中的「drawable」上按一下滑鼠右鍵,然後依序點選「New」>「Vector Asset」

e3b2bd6a495bc9.png

  1. 在「Asset Studio」對話方塊中搜尋星號圖示。請選取實心星型圖示。

「Select Icon」對話方塊顯示已選取星型圖示

  1. 將星星的顏色值變更為 625B71

Asset studio 對話方塊,顯示向量素材資源和顏色的設定

  1. 依序點選「Next」>「Finish」。
  2. 請注意,可繪項目會顯示在 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 資料夾下方" />

  1. 新增預覽可組合項,用來預覽 JuiceDetails 可組合項。
@Preview
@Composable
fun PreviewJuiceDetails() {
    JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}

含有果汁名稱、果汁說明和星等評分列

建立「刪除」按鈕可組合函式

  1. JuiceListAdapter.kt 中,新增另一個名為 DeleteButton() 的可組合函式,該函式會使用 lambda 回呼函式和修飾符。
  2. 將 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)
        )
    }
}
  1. 新增預覽函式,用來預覽刪除按鈕。
@Preview
@Composable
fun PreviewDeleteIcon() {
    DeleteButton({})
}

Android Studio 中的「刪除」圖示預覽畫面

5. 實作 ListItem 函式

現在,您已擁有顯示清單項目所需的所有可組合項,可以在版面配置中排列這些項目了。請注意您在上一個步驟中定義的 ListItem() 函式。

@Composable
fun ListItem(
   input: Juice,
   onEdit: (Juice) -> Unit,
   onDelete: (Juice) -> Unit,
   modifier: Modifier = Modifier
) {
}

JuiceListAdapter.kt 中,完成以下步驟來實作 ListItem() 函式。

  1. 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
   ) {

   }
}
  1. Row lambda 中,呼叫建立為子項元素的三個可組合函式 JuiceIconJuiceDetailsDeleteButton
JuiceIcon(input.color)
JuiceDetails(input, Modifier.weight(1f))
DeleteButton({})

Modifier.weight(1f) 傳遞至 JuiceDetails() 可組合項,確保在測量未加權的子項元素後,果汁詳細資料會佔用剩餘的水平空間。

  1. onDelete(input) lambda 和靠上對齊修飾符做為參數,傳遞至 DeleteButton 可組合函式。
DeleteButton(
   onDelete = {
       onDelete(input)
   },
   modifier = Modifier.align(Alignment.Top)
)
  1. 撰寫用來預覽 ListItem 可組合函式的預覽函式。
@Preview
@Composable
fun PreviewListItem() {
   ListItem(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4), {})
}

Android Studio 清單項目預覽畫面,含有甜菜根果汁的詳細資料

  1. 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),
       )
   }
}
  1. 執行應用程式。加入您最愛的果汁。請欣賞這酷炫的 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 開發人員說明文件

程式碼研究室 [中級]