教學課程

Jetpack Compose 教學課程

Jetpack Compose 是建構原生 Android UI 的新型工具包。Jetpack Compose 能以較少的程式碼、強大的工具和符合直覺的 Kotlin API,簡化並加快 Android 平台的 UI 開發作業。

在此教學課程中,您將建構具有宣告函式的簡易 UI 元件。過程中不需修改任何 XML 版面配置,也不必使用版面配置編輯器。您只要呼叫可組合函式來定義所需元素,Compose 編譯器即會完成其餘工作。

全文預覽
全文預覽

第 1 課:可組合函式

Jetpack Compose 是以可組合函式為基礎建構而成。您可以運用這些函式 以程式輔助的方式描述應用程式 UI 的外觀,並提供資料依附元件。 而非專注於 UI 的建構程序 (初始化元素、 然後將這個編號附加到父項等如要建立可組合函式,只需將 函式名稱的 @Composable 註解。

新增文字元素

首先,請下載最新版本的 Android Studio,建立應用程式方法是選取「New Project」,然後在 在「Phone and Tablet」類別中選取「Empty Activity」。 將應用程式命名為 ComposeTutorial,然後按一下「Finish」。預設 這個範本已包含部分 Compose 元素,但在本教學課程中,您將逐步進行建構 。

首先,顯示「Hello World!」方法是在 onCreate 方法。在這種情況下 封鎖及呼叫 Text 可組合函式。 setContent 區塊會定義活動的版面配置,其中 會呼叫可組合函式。可組合函式只能從其他可組合函式呼叫 函式。

Jetpack Compose 會使用 Kotlin 編譯器外掛程式,將這些可組合函式轉換為 調整應用程式的 UI 元素例如 Text 可組合函式 由 Compose UI 程式庫定義的函式會在螢幕上顯示文字標籤。

 import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             Text("Hello world!")         }     } }   
顯示預覽
隱藏預覽

定義可組合函式

如要讓函式組成,請新增 @Composable 註解。 如要試用這項功能,請定義 MessageCard 函式, 會傳遞一個名稱,並用來設定文字元素。

 // ... import androidx.compose.runtime.Composable  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             MessageCard("Android")         }     } }  @Composable fun MessageCard(name: String) {     Text(text = "Hello $name!") }    
顯示預覽
隱藏預覽

在 Android Studio 中預覽函式

@Preview 註解可讓您在 Android 中預覽可組合函式 不必建構應用程式並安裝到 Android 裝置或模擬器中,就能使用 Studio。 註解必須用於不接受參數的可組合函式。為此 因此您無法預覽 MessageCard 函式 請改為將第二個函式命名為 PreviewMessageCard,會呼叫 MessageCard 取代為適當的參數。將 @Preview 個註解早於 @Composable

 // ... import androidx.compose.ui.tooling.preview.Preview  @Composable fun MessageCard(name: String) {     Text(text = "Hello $name!") }  @Preview @Composable fun PreviewMessageCard() {     MessageCard("Android") }   
顯示預覽
隱藏預覽

重新建構您的專案。應用程式本身不會變更,因為新的 沒有在任何位置呼叫 PreviewMessageCard 函式 但 Android Studio 會新增預覽視窗,點選「分割」圖示 (設計/程式碼) 檢視畫面。這個視窗會顯示可組合函式建立的 UI 元素預覽畫面 標有 @Preview 註解的函式。更新 只要按一下預覽視窗頂端的重新整理按鈕,即可隨時預覽。

在 Android Studio 中預覽可組合函式
 import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             Text("Hello world!")         }     } }   
顯示預覽
隱藏預覽
 // ... import androidx.compose.runtime.Composable  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             MessageCard("Android")         }     } }  @Composable fun MessageCard(name: String) {     Text(text = "Hello $name!") }    
顯示預覽
隱藏預覽
 // ... import androidx.compose.ui.tooling.preview.Preview  @Composable fun MessageCard(name: String) {     Text(text = "Hello $name!") }  @Preview @Composable fun PreviewMessageCard() {     MessageCard("Android") }   
顯示預覽
隱藏預覽
在 Android Studio 中預覽可組合函式

第 2 課:版面配置

UI 元素具有階層結構,其他元素包含許多元素。在 Compose 中 從其他可組合函式呼叫可組合函式,藉此建構 UI 階層。

新增多段文字

到目前為止,您已建構第一個可組合函式並進行預覽!探索更多 Jetpack Compose 您會建構一個簡單的訊息畫面,內含一系列 都可以使用一些動畫展開

首先,顯示訊息作者的姓名和 訊息內容您必須先變更可組合函式參數,才能接受 Message 物件,而不是 String,然後新增其他 程式碼中的 Text 可組合函式 MessageCard 可組合函式。請務必更新預覽畫面

 // ...  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             MessageCard(Message("Android", "Jetpack Compose"))         }     } }  data class Message(val author: String, val body: String)  @Composable fun MessageCard(msg: Message) {     Text(text = msg.author)     Text(text = msg.body) }  @Preview @Composable fun PreviewMessageCard() {     MessageCard(         msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")     ) }    
顯示預覽
隱藏預覽

此程式碼會在內容檢視畫面中建立兩個文字元素。然而,由於您未提供 任何有關如何排列方式的資訊,文字元素會彼此疊加, 讓文字無法閱讀

使用資料欄

Column 函式可讓您垂直排列元素。 將 Column 新增至 MessageCard 函式。
您可以使用 Row 可以水平排列項目 Box 可堆疊元素。

 // ... import androidx.compose.foundation.layout.Column  @Composable fun MessageCard(msg: Message) {     Column {         Text(text = msg.author)         Text(text = msg.body)     } } 
顯示預覽
隱藏預覽

新增圖片元素

新增寄件者的個人資料相片,讓訊息內容更豐富。使用 資源管理工具 即可從相片庫匯入圖片,或使用這張相片。新增 Row 可組合函式具有良好的設計結構, Image 可組合函式。

 // ... import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.ui.res.painterResource  @Composable fun MessageCard(msg: Message) {     Row {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = "Contact profile picture",         )             Column {             Text(text = msg.author)             Text(text = msg.body)         }        }    }   
顯示預覽
隱藏預覽

設定版面配置

訊息版面配置的結構正確,但其元素之間的間距不適當,且圖片 太大!為了修飾或設定可組合函式,Compose 會使用修飾符。他們 可讓您變更可組合項的大小、版面配置、外觀或新增高階互動 例如將元素設為可點擊您可以為這些修飾符建立鏈結,產生功能更豐富的可組合項。您會用到 來改善版面配置

 // ... import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp  @Composable fun MessageCard(msg: Message) {     // Add padding around our message     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = "Contact profile picture",             modifier = Modifier                 // Set image size to 40 dp                 .size(40.dp)                 // Clip image to be shaped as a circle                 .clip(CircleShape)         )          // Add a horizontal space between the image and the column         Spacer(modifier = Modifier.width(8.dp))          Column {             Text(text = msg.author)             // Add a vertical space between the author and message texts             Spacer(modifier = Modifier.height(4.dp))             Text(text = msg.body)         }     } }   
顯示預覽
隱藏預覽
 // ...  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             MessageCard(Message("Android", "Jetpack Compose"))         }     } }  data class Message(val author: String, val body: String)  @Composable fun MessageCard(msg: Message) {     Text(text = msg.author)     Text(text = msg.body) }  @Preview @Composable fun PreviewMessageCard() {     MessageCard(         msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")     ) }    
顯示預覽
隱藏預覽
兩個重疊的 Text 可組合項預覽畫面
 // ... import androidx.compose.foundation.layout.Column  @Composable fun MessageCard(msg: Message) {     Column {         Text(text = msg.author)         Text(text = msg.body)     } } 
顯示預覽
隱藏預覽
 // ... import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.ui.res.painterResource  @Composable fun MessageCard(msg: Message) {     Row {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = "Contact profile picture",         )             Column {             Text(text = msg.author)             Text(text = msg.body)         }        }    }   
顯示預覽
隱藏預覽
 // ... import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp  @Composable fun MessageCard(msg: Message) {     // Add padding around our message     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = "Contact profile picture",             modifier = Modifier                 // Set image size to 40 dp                 .size(40.dp)                 // Clip image to be shaped as a circle                 .clip(CircleShape)         )          // Add a horizontal space between the image and the column         Spacer(modifier = Modifier.width(8.dp))          Column {             Text(text = msg.author)             // Add a vertical space between the author and message texts             Spacer(modifier = Modifier.height(4.dp))             Text(text = msg.body)         }     } }   
顯示預覽
隱藏預覽

第 3 課:Material Design

Compose 的設計宗旨是支援質感設計的原則。許多 UI 元素 立即可用的質感設計。在本課程中,您將學習如何使用 Material Design 設定應用程式樣式

使用 Material Design

訊息設計現在支援版面配置,但使用體驗尚有待改進。

Jetpack Compose 可讓您實作 Material Design 3 及其 UI 元素, 方塊。你將改善「MessageCard」的外觀 利用 Material Design 樣式建立可組合函式。

首先,使用 MessageCard 函式包裝 在專案 ComposeTutorialTheme 中建立的質感主題。 以及 Surface 請同時在 @PreviewsetContent 函式。這樣做可讓您的可組合項 沿用應用程式主題所定義的樣式,確保應用程式中的樣式一致。

Material Design 以三大核心為基礎建構而成:ColorTypographyShape。 您必須逐一新增。

注意:空白 Compose 活動範本會為您的專案產生預設主題, 可讓您自訂 MaterialTheme。 如果您將專案命名為 ComposeTutorial,您可以在以下路徑找到自訂主題: Theme.kt 檔案位於 ui.theme 子套件。

 // ...  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             ComposeTutorialTheme {                 Surface(modifier = Modifier.fillMaxSize()) {                     MessageCard(Message("Android", "Jetpack Compose"))                 }             }         }     } }  @Preview @Composable fun PreviewMessageCard() {     ComposeTutorialTheme {         Surface {             MessageCard(                 msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")             )         }     } }     
顯示預覽
隱藏預覽

顏色

使用 MaterialTheme.colorScheme 即可設定來自 經過包裝的主題。您可以在需要顏色的任何位置使用主題中的這些值。這個範例會使用動態主題設定顏色 (由裝置偏好設定定義)。 您可以在 MaterialTheme.kt 檔案中將 dynamicColor 設為 false,以變更這項設定。

設定標題樣式,並為圖片加上邊框。

 // ... import androidx.compose.foundation.border import androidx.compose.material3.MaterialTheme  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )         Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary            )             Spacer(modifier = Modifier.height(4.dp))            Text(text = msg.body)        }    } }    
顯示預覽
隱藏預覽

字體排版

MaterialTheme 提供 Material 字體排版樣式, 只要將這些可組合項新增至 Text 可組合函式即可。

 // ...  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )        Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary,                style = MaterialTheme.typography.titleSmall            )             Spacer(modifier = Modifier.height(4.dp))             Text(                text = msg.body,                style = MaterialTheme.typography.bodyMedium            )        }    } }    
顯示預覽
隱藏預覽

形狀

透過 Shape,您就可以新增最終點。首先,使用 郵件內文周圍 Surface 可組合函式。如此一來就可以自訂 訊息內文的形狀和高度此外,系統也會在訊息中新增邊框間距,以改善版面配置。

 // ... import androidx.compose.material3.Surface  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )        Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary,                style = MaterialTheme.typography.titleSmall            )             Spacer(modifier = Modifier.height(4.dp))             Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {                Text(                    text = msg.body,                    modifier = Modifier.padding(all = 4.dp),                    style = MaterialTheme.typography.bodyMedium                )            }        }    } }    
顯示預覽
隱藏預覽

啟用深色主題

深色主題 (或夜間模式),可避免夜間螢幕顯示亮度過強,或單純用來儲存 裝置電池支援 Material Design 讓 Jetpack Compose 能夠處理深色 主題。系統會自動使用質感設計的顏色、文字和背景 適應深色背景

您可以在檔案中建立多個預覽做為個別函式,或新增多個 相同函式的註解。

新增預覽註解並啟用夜間模式。

 // ... import android.content.res.Configuration  @Preview(name = "Light Mode") @Preview(     uiMode = Configuration.UI_MODE_NIGHT_YES,     showBackground = true,     name = "Dark Mode" ) @Composable fun PreviewMessageCard() {    ComposeTutorialTheme {     Surface {       MessageCard(         msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")       )     }    } }   
顯示預覽
隱藏預覽

IDE 產生的淺色和深色主題的顏色選項定義在 IDE 生成 Theme.kt 檔案。

目前為止,您已建立了一個訊息 UI 元素,可以顯示一張圖片和兩則文字不同的文字 樣式,在淺色和深色主題中都很美觀!

 // ... import android.content.res.Configuration  @Preview(name = "Light Mode") @Preview(     uiMode = Configuration.UI_MODE_NIGHT_YES,     showBackground = true,     name = "Dark Mode" ) @Composable fun PreviewMessageCard() {    ComposeTutorialTheme {     Surface {       MessageCard(         msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")       )     }    } }   
顯示預覽
隱藏預覽
 // ...  class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             ComposeTutorialTheme {                 Surface(modifier = Modifier.fillMaxSize()) {                     MessageCard(Message("Android", "Jetpack Compose"))                 }             }         }     } }  @Preview @Composable fun PreviewMessageCard() {     ComposeTutorialTheme {         Surface {             MessageCard(                 msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")             )         }     } }     
顯示預覽
隱藏預覽
 // ... import androidx.compose.foundation.border import androidx.compose.material3.MaterialTheme  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )         Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary            )             Spacer(modifier = Modifier.height(4.dp))            Text(text = msg.body)        }    } }    
顯示預覽
隱藏預覽
 // ...  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )        Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary,                style = MaterialTheme.typography.titleSmall            )             Spacer(modifier = Modifier.height(4.dp))             Text(                text = msg.body,                style = MaterialTheme.typography.bodyMedium            )        }    } }    
顯示預覽
隱藏預覽
 // ... import androidx.compose.material3.Surface  @Composable fun MessageCard(msg: Message) {    Row(modifier = Modifier.padding(all = 8.dp)) {        Image(            painter = painterResource(R.drawable.profile_picture),            contentDescription = null,            modifier = Modifier                .size(40.dp)                .clip(CircleShape)                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)        )        Spacer(modifier = Modifier.width(8.dp))         Column {            Text(                text = msg.author,                color = MaterialTheme.colorScheme.secondary,                style = MaterialTheme.typography.titleSmall            )             Spacer(modifier = Modifier.height(4.dp))             Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {                Text(                    text = msg.body,                    modifier = Modifier.padding(all = 4.dp),                    style = MaterialTheme.typography.bodyMedium                )            }        }    } }    
顯示預覽
隱藏預覽
 // ... import android.content.res.Configuration  @Preview(name = "Light Mode") @Preview(     uiMode = Configuration.UI_MODE_NIGHT_YES,     showBackground = true,     name = "Dark Mode" ) @Composable fun PreviewMessageCard() {    ComposeTutorialTheme {     Surface {       MessageCard(         msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")       )     }    } }   
顯示預覽
隱藏預覽
預覽畫面同時顯示淺色和深色主題的可組合項。

第 4 課:清單和動畫

清單和動畫會出現在應用程式中的任何地方。本課程會說明 Compose 可讓您輕鬆建立清單,並增添動畫效果。

建立訊息清單

只顯示一則訊息會感覺有點孤單,因此我們可以變更對話內容,讓 1 則訊息您必須建立 Conversation 函式 顯示多則訊息針對這個用途,請使用 Compose 的 LazyColumn LazyRow。這些可組合函式只會轉譯元素 顯示在畫面上,因此對於較長清單來說是非常有效率。

在這個程式碼片段中,您可以看到 LazyColumn 具有 items 位兒童。這需要 List 做為參數及其 lambda 收到我們命名為 message 的參數 (可以是 可以隨意命名) 也就是 Message 的例項。 簡單來說,系統會針對所提供項目中的每個項目呼叫這個 lambda List。複製 資料集範例 以便快速展開對話

 // ... import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items  @Composable fun Conversation(messages: List<Message>) {     LazyColumn {         items(messages) { message ->             MessageCard(message)         }     } }  @Preview @Composable fun PreviewConversation() {     ComposeTutorialTheme {         Conversation(SampleData.conversationSample)     } }    
顯示預覽
隱藏預覽

展開訊息時以動畫呈現訊息

對話變得更有趣。現在是時候製作動畫了!您將新增 能夠展開訊息以顯示更多內容,同時以動畫呈現內容大小和 背景顏色。如要儲存此本機 UI 狀態,您必須追蹤訊息是否 是否已展開。如要追蹤狀態變更,請使用函式 「remember」和 mutableStateOf

可組合函式可以使用 remember,並追蹤傳遞至 mutableStateOf。可組合函式 (及其子項) 並在更新該值後,自動重新繪製這個狀態。這種訓練方式稱為 recomposition

使用 Compose 的狀態 API,例如 remember 以及 mutableStateOf,任何狀態變更都會自動更新 UI。

注意:您必須新增以下匯入項目,才能正確使用 Kotlin 的 委派屬性語法 (by 關鍵字)。Alt+Enter 或 Option + Enter 鍵,即可新增這些項目 不必確保憑證管理是否適當 因為 Google Cloud 會為您管理安全性
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue

 // ... import androidx.compose.foundation.clickable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue  class MainActivity : ComponentActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContent {            ComposeTutorialTheme {                Conversation(SampleData.conversationSample)            }        }    } }  @Composable fun MessageCard(msg: Message) {     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = null,             modifier = Modifier                 .size(40.dp)                 .clip(CircleShape)                 .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)         )         Spacer(modifier = Modifier.width(8.dp))          // We keep track if the message is expanded or not in this         // variable         var isExpanded by remember { mutableStateOf(false) }          // We toggle the isExpanded variable when we click on this Column         Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {             Text(                 text = msg.author,                 color = MaterialTheme.colorScheme.secondary,                 style = MaterialTheme.typography.titleSmall             )              Spacer(modifier = Modifier.height(4.dp))              Surface(                 shape = MaterialTheme.shapes.medium,                 shadowElevation = 1.dp,             ) {                 Text(                     text = msg.body,                     modifier = Modifier.padding(all = 4.dp),                     // If the message is expanded, we display all its content                     // otherwise we only display the first line                     maxLines = if (isExpanded) Int.MAX_VALUE else 1,                     style = MaterialTheme.typography.bodyMedium                 )             }         }     } }    
顯示預覽
隱藏預覽

您現在可以根據下列項目變更郵件內容的背景: isExpanded。您會使用 clickable 修飾符來處理 可組合函式。請不要只是切換網站的背景顏色 Surface,您將要加上背景顏色的動畫效果 逐漸修改該函式的值 MaterialTheme.colorScheme.surfaceMaterialTheme.colorScheme.primary,反之亦然。方法如下 您將使用 animateColorAsState 函式。最後 會使用 animateContentSize 修飾符建立動畫 訊息容器大小一致:

 // ... import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateContentSize  @Composable fun MessageCard(msg: Message) {     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = null,             modifier = Modifier                 .size(40.dp)                 .clip(CircleShape)                 .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)         )         Spacer(modifier = Modifier.width(8.dp))          // We keep track if the message is expanded or not in this         // variable         var isExpanded by remember { mutableStateOf(false) }         // surfaceColor will be updated gradually from one color to the other         val surfaceColor by animateColorAsState(             if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,         )          // We toggle the isExpanded variable when we click on this Column         Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {             Text(                 text = msg.author,                 color = MaterialTheme.colorScheme.secondary,                 style = MaterialTheme.typography.titleSmall             )              Spacer(modifier = Modifier.height(4.dp))              Surface(                 shape = MaterialTheme.shapes.medium,                 shadowElevation = 1.dp,                 // surfaceColor color will be changing gradually from primary to surface                 color = surfaceColor,                 // animateContentSize will change the Surface size gradually                 modifier = Modifier.animateContentSize().padding(1.dp)             ) {                 Text(                     text = msg.body,                     modifier = Modifier.padding(all = 4.dp),                     // If the message is expanded, we display all its content                     // otherwise we only display the first line                     maxLines = if (isExpanded) Int.MAX_VALUE else 1,                     style = MaterialTheme.typography.bodyMedium                 )             }         }     } }    
顯示預覽
隱藏預覽
 // ... import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items  @Composable fun Conversation(messages: List<Message>) {     LazyColumn {         items(messages) { message ->             MessageCard(message)         }     } }  @Preview @Composable fun PreviewConversation() {     ComposeTutorialTheme {         Conversation(SampleData.conversationSample)     } }    
顯示預覽
隱藏預覽
 // ... import androidx.compose.foundation.clickable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue  class MainActivity : ComponentActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContent {            ComposeTutorialTheme {                Conversation(SampleData.conversationSample)            }        }    } }  @Composable fun MessageCard(msg: Message) {     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = null,             modifier = Modifier                 .size(40.dp)                 .clip(CircleShape)                 .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)         )         Spacer(modifier = Modifier.width(8.dp))          // We keep track if the message is expanded or not in this         // variable         var isExpanded by remember { mutableStateOf(false) }          // We toggle the isExpanded variable when we click on this Column         Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {             Text(                 text = msg.author,                 color = MaterialTheme.colorScheme.secondary,                 style = MaterialTheme.typography.titleSmall             )              Spacer(modifier = Modifier.height(4.dp))              Surface(                 shape = MaterialTheme.shapes.medium,                 shadowElevation = 1.dp,             ) {                 Text(                     text = msg.body,                     modifier = Modifier.padding(all = 4.dp),                     // If the message is expanded, we display all its content                     // otherwise we only display the first line                     maxLines = if (isExpanded) Int.MAX_VALUE else 1,                     style = MaterialTheme.typography.bodyMedium                 )             }         }     } }    
顯示預覽
隱藏預覽
 // ... import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateContentSize  @Composable fun MessageCard(msg: Message) {     Row(modifier = Modifier.padding(all = 8.dp)) {         Image(             painter = painterResource(R.drawable.profile_picture),             contentDescription = null,             modifier = Modifier                 .size(40.dp)                 .clip(CircleShape)                 .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)         )         Spacer(modifier = Modifier.width(8.dp))          // We keep track if the message is expanded or not in this         // variable         var isExpanded by remember { mutableStateOf(false) }         // surfaceColor will be updated gradually from one color to the other         val surfaceColor by animateColorAsState(             if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,         )          // We toggle the isExpanded variable when we click on this Column         Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {             Text(                 text = msg.author,                 color = MaterialTheme.colorScheme.secondary,                 style = MaterialTheme.typography.titleSmall             )              Spacer(modifier = Modifier.height(4.dp))              Surface(                 shape = MaterialTheme.shapes.medium,                 shadowElevation = 1.dp,                 // surfaceColor color will be changing gradually from primary to surface                 color = surfaceColor,                 // animateContentSize will change the Surface size gradually                 modifier = Modifier.animateContentSize().padding(1.dp)             ) {                 Text(                     text = msg.body,                     modifier = Modifier.padding(all = 4.dp),                     // If the message is expanded, we display all its content                     // otherwise we only display the first line                     maxLines = if (isExpanded) Int.MAX_VALUE else 1,                     style = MaterialTheme.typography.bodyMedium                 )             }         }     } }    
顯示預覽
隱藏預覽

後續步驟

恭喜,您已完成 Compose 教學課程!您只用了不到 100 行程式碼就建構了簡易即時通訊螢幕,非常有效率!畫面上展示的動畫訊息清單可供展開,包含圖片和文字,採用質感設計原則和深色主題,並具備預覽功能。

您目前已瞭解的內容如下:

  • 定義可組合函式
  • 在組合中新增不同元素
  • 使用版面配置元件建構 UI 元件
  • 使用修飾詞擴充可組合項
  • 建立高效率清單
  • 持續追蹤並修改狀態
  • 在可組合項上新增使用者互動
  • 在展開時為訊息加入動畫效果

如要深入瞭解這些步驟,請參閱下列資源。

後續步驟

設定
您已完成 Compose 教學課程,可開始使用 Compose 進行建構。
課程
歡迎查看我們專為程式碼研究室和影片提供的一系列課程,可協助您學習及精進 Jetpack Compose。