Jetpack Compose 基礎知識

教程取自于Google官方課程之Jetpack Compose 基礎知識


1. 準備工作

Jetpack Compose 是一款新型工具包,旨在幫助簡化界面開發。該工具包將響應式編程模型與簡潔易用的 Kotlin 編程語言相結合,并采用完全聲明式的代碼編寫方式,讓您可以通過調用一系列函數來描述界面,這些函數會將數據轉換為界面層次結構。當底層數據發生變化時,框架會自動重新執行這些函數,為您更新界面層次結構。

Compose 應用由可組合函數構成。可組合函數即帶有 @Composable 標記的常規函數,這些函數可以調用其他可組合函數。使用一個函數就可以創建一個新的界面組件。該注解會告知 Compose 為函數添加特殊支持,以便后續更新和維護界面。借助 Compose,您可以將代碼設計成多個小代碼塊。可組合函數通常簡稱為“可組合項”。

通過創建可重用的小型可組合項,您可以輕松構建應用中所用界面元素的庫。每個可組合項對應于屏幕的一個部分,可以單獨修改。

注意:在本 Codelab 中,“界面組件”、“可組合函數”和“可組合項”幾個術語可以互換使用來指代同一個概念。

2. 啟動新的 Compose 項目

如需啟動新的 Compose 項目,請打開 Android Studio Bumblebee,然后選擇 Start a new Android Studio project,如下所示:

新的 Compose 項目

如果系統未顯示上述界面,請依次進入 File > New > New Project。
創建新項目時,請從可用模板中選擇 Empty Compose Activity。
Empty Compose Activity

點擊 Next,然后照常配置項目,并將其命名為 Basics Codelab。請確保您選擇的 minimumSdkVersion 至少為 API 級別 21,這是 Compose 支持的最低 API 級別。

注意:如需詳細了解如何使用空 activity 設置 Compose,或如何將其添加到現有項目,請查看此文檔
選擇 Empty Compose Activity 模板后,會在項目中為您生成以下代碼:

  • 該項目已配置為使用 Compose。
  • 已創建 AndroidManifest.xml 文件。
  • build.gradle 和 app/build.gradle 文件包含 Compose 所需的選項和依賴項。

同步項目后,請打開 MainActivity.kt 并查看代碼。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BasicsCodelabTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
private fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    BasicsCodelabTheme {
        Greeting("Android")
    }
}

警告:setContent 中使用的應用主題取決于項目名稱。本 Codelab 假定項目名稱為 LayoutsCodelab。如果您從 Codelab 中復制并粘貼代碼,請記得使用 ui/Theme.kt 文件中提供的主題名稱來更新 BasicsCodelabTheme。本 Codelab 后面會講到如何設置主題。

本 Codelab 的解決方案
您可以從 GitHub 獲取本 Codelab 的解決方案代碼:https://github.com/googlecodelabs/android-compose-codelabs/archive/main.zip
您可以在 BasicsCodelab 項目中找到解決方案代碼。建議您按照自己的節奏逐步完成 Codelab,必要時再查看解決方案。在此 Codelab 的學習過程中,我們會為您提供需要添加到項目的代碼段。

3. Compose 使用入門

了解 Android Studio 為您生成的與 Compose 相關的各種類和方法。

可組合函數

可組合函數是帶有 @Composable 注解的常規函數。這類函數自身可以調用其他 @Composable 函數。我們會展示如何為 Greeting 函數添加 @Composable 標記。此函數會生成一段顯示給定輸入 String 的界面層次結構。Text 是由庫提供的可組合函數。

@Composable
private fun Greeting(name: String) {
   Text(text = "Hello $name!")
}

注意:可組合函數是帶有 @Composable 注解的 Kotlin 函數,如上述代碼段所示。

Android 應用中的 Compose
使用 Compose 時,Activities 仍然是 Android 應用的入口點。在我們的項目中,用戶打開應用時會啟動 MainActivity(如 AndroidManifest.xml 文件中所指定)。您可以使用 setContent 來定義布局,但不同于在傳統 View 系統中使用 XML 文件,您將在該函數中調用可組合函數。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BasicsCodelabTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    Greeting("Android")
                }
            }
        }
    }
}

BasicsCodelabTheme 是為可組合函數設置樣式的一種方式。有關詳細內容,請參閱設置應用主題部分。如需查看文本在屏幕上的顯示效果,您可以在模擬器或設備上運行該應用,或使用 Android Studio 預覽進行查看。

若要使用 Android Studio 預覽,您只需使用 @Preview 注解標記所有無參數可組合函數或采用默認參數的函數,然后構建您的項目即可。現在 MainActivity.kt 文件中已經包含了一個 Preview Composable 函數。您可以在同一個文件中包含多個預覽,并為它們指定名稱。

@Preview(showBackground = true, name = "Text preview")
@Composable
fun DefaultPreview() {
    BasicsCodelabTheme {
        Greeting(name = "Android")
    }
}
Preview

注意:在此項目中導入與 Jetpack Compose 相關的類時,請從以下位置導入:
androidx.compose.*(針對編譯器和運行時類)

androidx.compose.ui.*(針對界面工具包和庫)

4. 調整界面

首先,為 Greeting 設置不同的背景顏色。為此,您可以用 Surface 包圍 Text 可組合項。Surface 會采用一種顏色,因此請使用 MaterialTheme.colors.primary。

注意:SurfaceMaterialTheme 是與 Material Design 相關的概念。Material Design 是 Google 提供的一個設計系統,旨在幫助您構建界面和體驗。

@Composable
private fun Greeting(name: String) {
    Surface(color = MaterialTheme.colors.primary) {
        Text (text = "Hello $name!")
    }
}

嵌套在 Surface 內的組件將在該背景顏色之上繪制。
將上述代碼添加到項目后,您會在 Android Studio 的右上角看到 Build & Refresh 按鈕。點按該按鈕或構建項目即可在預覽中查看新更改。



您可以在預覽中查看新更改:



您可能忽略了一個重要的細節:文字現在是白色的。我們是何時對此進行定義的?

我們并沒有對此進行過定義!Material 組件(例如 androidx.compose.material.Surface)旨在提供應用中可能需要的常見功能(例如為文本選擇適當的顏色),讓您獲得更好的體驗。我們之所以說 Material 很實用,是因為它提供在大多數應用中都會用到的實用默認值和模式。Compose 中的 Material 組件是在其他基礎組件(位于 androidx.compose.foundation 中)的基礎上構建的。如果您需要更高的靈活性,也可以從您的應用組件中訪問這些組件。

在這種情況下,Surface 會了解,當該背景設置為 primary 顏色后,其上的任何文本都應使用 onPrimary 顏色,此顏色也在主題中進行了定義。如需了解詳情,請參閱設置應用主題部分。

注意:如需查看 Compose 中 Material 組件的交互式列表,請查看 Compose Material Catalog 應用。
修飾符
大多數 Compose 界面元素(例如 Surface 和 Text)都接受可選的 modifier 參數。修飾符會指示界面元素如何在其父級布局中放置、顯示或表現。

例如,padding 修飾符會在其修飾的元素周圍應用一定的空間。您可以使用 Modifier.padding() 創建內邊距修飾符。

現在,為屏幕上的 Text 添加內邊距:

import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
...
點擊 Build & Refresh 即可查看新更改。
@Composable
private fun Greeting(name: String) {
    Surface(color = MaterialTheme.colors.primary) {
        Text(text = "Hello $name!", modifier = Modifier.padding(24.dp))
    }
}

點擊 Build & Refresh 即可查看新更改。


5. 重復使用可組合項

您添加到界面的組件越多,創建的嵌套層級就越多。如果函數變得非常大,可能會影響可讀性。通過創建可重用的小型組件,可以輕松構建應用中所用界面元素的庫。每個組件對應于屏幕的一個部分,可以單獨修改。

創建一個名為 MyApp 的可組合項,該組合項中包含問候語。

@Composable
private fun MyApp() {
    Surface(color = MaterialTheme.colors.background) {
        Greeting("Android")
    }
}

這樣一來,由于現在可以重復使用 MyApp 可組合項,您就可以省去 onCreate 回調和預覽,從而避免重復編寫代碼。您的 MainActivity.kt 文件應如下所示:

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.codelab.basicstep1.ui.theme.BasicsCodelabTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BasicsCodelabTheme {
                MyApp()
            }
        }
    }
}

@Composable
private fun MyApp() {
    Surface(color = MaterialTheme.colors.background) {
        Greeting("Android")
    }
}

@Composable
private fun Greeting(name: String) {
    Surface(color = MaterialTheme.colors.primary) {
        Text(text = "Hello $name!", modifier = Modifier.padding(24.dp))
    }
}

@Preview(showBackground = true)
@Composable
private fun DefaultPreview() {
    BasicsCodelabTheme {
        MyApp()
    }
}

6. 創建列和行

Compose 中的三個基本標準布局元素是 ColumnRowBox 可組合項。


它們是接受可組合內容的可組合函數,因此您可以在其中放置內容。例如,Column 中的每個子級都將垂直放置。

// Don't copy over
Column {
    Text("First row")
    Text("Second row")
}

現在嘗試更改 Greeting,使其顯示包含兩個文本元素的列,如以下示例中所示:



請注意,您可能需要移動周圍的內邊距。

將您的結果與此解決方案進行比較:

import androidx.compose.foundation.layout.Column
...

@Composable
private fun Greeting(name: String) {
    Surface(color = MaterialTheme.colors.primary) {
        Column(modifier = Modifier.padding(24.dp)) {
            Text(text = "Hello,")
            Text(text = name)
        }
    }
}

Compose 和 Kotlin
可組合函數可以像 Kotlin 中的其他函數一樣使用。這會使界面構建變得非常有效,因為您可以添加語句來影響界面的顯示方式。

例如,您可以使用 for 循環向 Column 中添加元素:

@Composable
fun MyApp(names: List<String> = listOf("World", "Compose")) {
    Column {
        for (name in names) {
            Greeting(name = name)
        }
    }
}

您尚未設置可組合項的尺寸,也未對可組合項的大小添加任何限制,因此每一行僅占用可能的最小空間,預覽時的效果也是如此。讓我們更改預覽效果,以模擬小屏幕手機的常見寬度 320dp。按如下所示向 @Preview 注解添加 widthDp 參數:

@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreview() {
    BasicsCodelabTheme {
        MyApp()
    }
}


修飾符在 Compose 中使用得非常廣泛,現在我們來練習更高級的用法:嘗試使用 fillMaxWidthpadding 修飾符復制以下布局。

現在,將您的代碼與解決方案進行比較:

@Composable
fun MyApp(names: List<String> = listOf("World", "Compose")) {
    Column(modifier = Modifier.padding(vertical = 4.dp)) {
        for (name in names) {
            Greeting(name = name)
        }
    }
}

@Composable
private fun Greeting(name: String) {
    Surface(
        color = MaterialTheme.colors.primary,
        modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Column(modifier = Modifier.fillMaxWidth().padding(24.dp)) {
            Text(text = "Hello, ")
            Text(text = name)
        }
    }
}

請注意:

修飾符可以包含重載,因而具有相應的優勢,例如您可以指定不同的方式來創建內邊距。
若要向一個元素添加多個修飾符,您只需要將它們鏈接起來即可。
有多種方式可以實現此結果,因此,如果您的代碼與此代碼段不同,并不表示您的代碼就是錯的。不過,為了繼續完成此 Codelab,仍請復制并粘貼此代碼。

添加按鈕
接下來,您將添加一個用于展開 Greeting 的可點擊元素,因此需要先添加對應的按鈕。您的目標是要創建以下布局:


Button 是 Material 軟件包提供的一種可組合項,它采用可組合項作為最后一個參數。由于尾隨 lambda 可以移到括號之外,因此您可以向按鈕添加任何內容作為子級,例如 Text

// Don't copy yet
Button(
    onClick = { } // You'll learn about this callback later
) {
    Text("Show less")
}

注意:Compose 根據 Material Design 按鈕規范提供了不同類型的 ButtonButtonOutlinedButtonTextButton。在本示例中,您將使用包圍 Text 作為 Button 內容的 OutlinedButton

為了實現這一點,您需要學習如何在行尾放置可組合項。由于沒有 alignEnd 修飾符,因此您需要在開始時為該可組合項賦予一定的 weight。weight 修飾符會讓元素填滿所有可用空間,使其“具有彈性”,也就是會推開其他沒有權重的元素(即“無彈性”元素)。該修飾符還會使 fillMaxWidth 修飾符變得多余。

現在嘗試添加該按鈕,并按照上述圖片中所示放置該按鈕。

下面列出了對應的解決方案代碼:

import androidx.compose.material.Button
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
...

@Composable
private fun Greeting(name: String) {

    Surface(
        color = MaterialTheme.colors.primary,
        modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Row(modifier = Modifier.padding(24.dp)) {
            Column(modifier = Modifier.weight(1f)) {
                Text(text = "Hello, ")
                Text(text = name)
            }
            OutlinedButton(
                onClick = { /* TODO */ }
            ) {
                Text("Show more")
            }
        }
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容