Thêm ảnh động đơn giản nhờ Jetpack Compose

1. Trước khi bắt đầu

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách thêm một ảnh động đơn giản vào ứng dụng Android. Ảnh động có thể giúp ứng dụng tăng tính tương tác, đồng thời thú vị và dễ hiểu hơn. Khi bạn tạo ảnh động cho từng điểm cập nhật trên màn hình hiện nhiều thông tin, người dùng có thể thấy được nội dung nào đã thay đổi.

Có nhiều loại ảnh động có thể dùng trong giao diện người dùng của ứng dụng. Các mục có thể hiện dần trong lúc xuất hiện và mờ dần trong lúc biến mất, chúng có thể di chuyển vào hoặc ra khỏi màn hình, hoặc có thể biến đổi theo những cách thú vị. Điều này giúp giao diện người dùng của ứng dụng trở nên sinh động và dễ sử dụng.

Ảnh động cũng có thể giúp giao diện ứng dụng của bạn trở nên trau chuốt hơn, vừa trang nhã vừa hữu ích cho người dùng.

Điều kiện tiên quyết

  • Kiến thức về Kotlin, bao gồm các hàm, hàm lambda và các thành phần kết hợp không có trạng thái.
  • Kiến thức cơ bản về cách xây dựng bố cục trong Jetpack Compose.
  • Kiến thức cơ bản về cách tạo danh sách trong Jetpack Compose.
  • Kiến thức cơ bản về Material Design.

Kiến thức bạn sẽ học được

  • Cách tạo ảnh động đơn giản có hiệu ứng lò xo bằng Jetpack Compose.

Sản phẩm bạn sẽ tạo ra

Bạn cần có

  • Phiên bản ổn định mới nhất của Android Studio.
  • Kết nối Internet để tải đoạn mã khởi đầu xuống.

2. Tổng quan về ứng dụng

Trong lớp học lập trình Dùng Jetpack Compose để tuỳ chỉnh giao diện Material, bạn đã dùng Material Design để tạo ứng dụng Woof. Ứng dụng này cho thấy danh sách các chú chó và thông tin về chúng.

36c6cabd93421a92.png

Trong lớp học lập trình này, bạn sẽ thêm ảnh động vào ứng dụng Woof cùng với thông tin sở thích sẽ xuất hiện khi bạn mở rộng mục danh sách. Bạn cũng sẽ thêm ảnh động lò xo để tạo hiệu ứng cho mục danh sách được mở rộng.

c0d0a52463332875.gif

Lấy mã khởi đầu

Để bắt đầu, hãy tải mã khởi đầu xuống:

Ngoài ra, bạn có thể sao chép kho lưu trữ GitHub cho mã:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout material

Bạn có thể duyệt xem mã này trong Kho lưu trữ GitHub Woof app.

3. Thêm biểu tượng mở rộng

Trong phần này, bạn sẽ thêm biểu tượng Mở rộng 30c384f00846e69b.pngThu gọn f88173321938c003.png vào ứng dụng.

def59d71015c0fbe.png

Biểu tượng

Biểu tượng (icon) là các ký hiệu giúp người dùng hiểu giao diện người dùng qua việc truyền đạt chức năng dự định dưới dạng hình ảnh trực quan. Biểu tượng thường lấy cảm hứng từ đối tượng trong thế giới thực người dùng thường bắt gặp. Thiết kế biểu tượng thường giảm tối đa các chi tiết để tạo cảm giác quen thuộc cho người dùng. Ví dụ: bút chì trong thế giới thực được dùng để viết, vì vậy, biểu tượng có hình bút chì thường biểu thị thao tác tạo hoặc chỉnh sửa.

Chiếc bút chì trên quyển vở Ảnh chụp của Angelina Litvin trên Unsplash

Biểu tượng bút chì đen trắng

Material Design cung cấp các danh mục chứa một số biểu tượng phổ biến, đáp ứng được hầu hết nhu cầu của bạn.

Thư viện biểu tượng Material

Thêm phần phụ thuộc vào Gradle

Thêm phần phụ thuộc thư viện material-icons-extended vào dự án của bạn. Bạn sẽ sử dụng các biểu tượng Icons.Filled.ExpandLess 30c384f00846e69b.pngIcons.Filled.ExpandMore f88173321938c003.png của thư viện này.

  1. Trong ngăn Project (Dự án), hãy mở Gradle Scripts > build.gradle (Module :app) (Tập lệnh Gradle > build.gradle (Mô-đun: :app).
  2. Di chuyển đến cuối tệp build.gradle.kts (Module :app). Trong khối dependencies{}, hãy thêm dòng sau:
implementation("androidx.compose.material:material-icons-extended")

Thêm thành phần kết hợp biểu tượng

Thêm một hàm để cho thấy biểu tượng Mở rộng trong thư viện biểu tượng Material rồi sử dụng biểu tượng đó làm nút.

  1. Trong MainActivity.kt, sau hàm DogItem(), hãy tạo một hàm có khả năng kết hợp mới là DogItemButton().
  2. Truyền Boolean vào trạng thái mở rộng, biểu thức lambda cho nút trình xử lý onClick và Modifier (không bắt buộc) như sau:
@Composable
private fun DogItemButton(
   expanded: Boolean,
   onClick: () -> Unit,
   modifier: Modifier = Modifier
) {
 

}
  1. Bên trong hàm DogItemButton(), hãy thêm một thành phần kết hợp IconButton() chấp nhận tham số có tên onClick, một hàm lambda sử dụng cú pháp lambda theo sau, được gọi khi người dùng nhấn vào biểu tượng này và modifier (không bắt buộc). Đặt IconButton's onClickmodifier value parameters bằng với giá trị được truyền vào DogItemButton.
@Composable
private fun DogItemButton(
   expanded: Boolean,
   onClick: () -> Unit,
   modifier: Modifier = Modifier
){
   IconButton(
       onClick = onClick,
       modifier = modifier
   ) {

   }
}
  1. Bên trong khối lambda IconButton(), hãy thêm một thành phần kết hợp Icon và đặt imageVector value-parameter thành Icons.Filled.ExpandMore. Đây là nội dung xuất hiện ở cuối mục danh sách f88173321938c003.png. Android Studio cho bạn thấy cảnh báo về các tham số thành phần kết hợp Icon() mà bạn sẽ khắc phục trong bước tiếp theo.
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.Icons
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton

IconButton(
   onClick = onClick,
   modifier = modifier
) {
   Icon(
       imageVector = Icons.Filled.ExpandMore
   )
}
  1. Thêm tham số giá trị tint rồi đặt màu của biểu tượng thành MaterialTheme.colorScheme.secondary. Thêm tham số đã đặt tên contentDescription rồi đặt tham số đó thành tài nguyên chuỗi R.string.expand_button_content_description.
IconButton(
   onClick = onClick,
   modifier = modifier
){
   Icon(
       imageVector = Icons.Filled.ExpandMore,
       contentDescription = stringResource(R.string.expand_button_content_description),
       tint = MaterialTheme.colorScheme.secondary
   )
}

Hiển thị biểu tượng

Cho thấy thành phần kết hợp DogItemButton() bằng cách thêm thành phần này vào bố cục.

  1. Ở đầu DogItem(), hãy thêm var để lưu trạng thái mở rộng của mục danh sách. Đặt giá trị ban đầu thành false.
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

var expanded by remember { mutableStateOf(false) }
  1. Cho thấy nút biểu tượng trong mục danh sách. Trong thành phần kết hợp DogItem(), ở cuối khối Row, sau phương thức gọi đến DogInformation(), hãy thêm DogItemButton(). Truyền ở trạng thái expanded và hàm lambda trống cho phương thức gọi lại. Bạn sẽ xác định hành động onClick trong bước sau.
Row(
   modifier = Modifier
       .fillMaxWidth()
       .padding(dimensionResource(R.dimen.padding_small))
) {
   DogIcon(dog.imageResourceId)
   DogInformation(dog.name, dog.age)
   DogItemButton(
       expanded = expanded,
       onClick = { /*TODO*/ }
   )
}
  1. Xem WoofPreview() trong ngăn Design (Thiết kế).

5bbf09cd2828b6.png

Lưu ý rằng nút mở rộng không được căn chỉnh với cuối mục danh sách. Bạn sẽ khắc phục được vấn đề đó trong bước tiếp theo.

Căn chỉnh nút mở rộng

Để căn chỉnh nút có biểu tượng mở rộng ở cuối mục trong danh sách, bạn cần thêm một khoảng trống (spacer) tuỳ chỉnh hợp lý trong bố cục bằng thuộc tính Modifier.weight().

Trong ứng dụng Woof, mỗi hàng trong danh sách chứa một hình ảnh chú chó, thông tin về chú chó và một nút mở rộng. Bạn sẽ thêm một thành phần kết hợp Spacer trước nút mở rộng có trọng số 1f để căn chỉnh đúng biểu tượng nút. Vì khoảng trống tuỳ chỉnh là thành phần con duy nhất có trọng số trong hàng, nên thành phần này sẽ lấp đầy khoảng trống còn lại trong hàng sau khi xét đến của thành phần con không có trọng số khác.

733f6d9ef2939ab5.png

Thêm khoảng trống vào hàng của mục trong danh sách

  1. Trong DogItem(), từ DogInformation() đến DogItemButton(), hãy thêm một Spacer. Truyền trong Modifier bằng weight(1f). Modifier.weight() làm cho khoảng trống lấp đầy khoảng trống còn lại trong hàng.
import androidx.compose.foundation.layout.Spacer

Row(
   modifier = Modifier
       .fillMaxWidth()
       .padding(dimensionResource(R.dimen.padding_small))
) {
   DogIcon(dog.imageResourceId)
   DogInformation(dog.name, dog.age)
   Spacer(modifier = Modifier.weight(1f))
   DogItemButton(
       expanded = expanded,
       onClick = { /*TODO*/ }
   )
}
  1. Xem WoofPreview() trong ngăn Design (Thiết kế). Xin lưu ý rằng nút mở rộng hiện đã được căn chỉnh vào cuối mục danh sách.

8df42b9d85a5dbaa.png

4. Thêm tiện ích có thể hoàn thành để hiển thị sở thích

Trong nhiệm vụ này, bạn sẽ thêm các thành phần kết hợp Text để cho thấy thông tin về sở thích của chú chó.

bba8146c6332cc37.png

  1. Tạo một hàm có khả năng kết hợp mới tên là DogHobby(). Hàm này sẽ lấy mã nhận dạng tài nguyên chuỗi xác định sở thích của một chú chó và một thuộc tính Modifier tuỳ ý.
@Composable
fun DogHobby(
   @StringRes dogHobby: Int,
   modifier: Modifier = Modifier
) {
}
  1. Bên trong hàm DogHobby(), hãy tạo một Column rồi truyền đối tượng sửa đổi vào DogHobby().
@Composable
fun DogHobby(
   @StringRes dogHobby: Int,
   modifier: Modifier = Modifier
){
   Column(
       modifier = modifier
   ) { 

   }
}
  1. Bên trong khối Column, hãy thêm 2 thành phần kết hợp Text – một thành phần để cho thấy văn bản About (Giới thiệu) ở trên thông tin về sở thích và một thành phần khác để cho thấy thông tin về sở thích.

Đặt text của thành phần đầu tiên thành about trong tệp strings.xml rồi đặt style thành labelSmall. Đặt text của thành phần thứ hai thành dogHobby được truyền vào rồi đặt style thành bodyLarge.

Column(
   modifier = modifier
) {
   Text(
       text = stringResource(R.string.about),
       style = MaterialTheme.typography.labelSmall
   )
   Text(
       text = stringResource(dogHobby),
       style = MaterialTheme.typography.bodyLarge
   )
}
  1. Trong DogItem(), thành phần kết hợp DogHobby() sẽ nằm dưới Row chứa DogIcon(), DogInformation(), Spacer()DogItemButton(). Để làm việc này, hãy gói Row bằng Column để có thể thêm sở thích bên dưới Row.
Column() {
   Row(
       modifier = Modifier
           .fillMaxWidth()
           .padding(dimensionResource(R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
       Spacer(modifier = Modifier.weight(1f))
       DogItemButton(
           expanded = expanded,
           onClick = { /*TODO*/ }
       )
   }
}
  1. Thêm DogHobby() sau Row làm thành phần con thứ hai của Column. Truyền vào dog.hobbies chứa sở thích riêng của chú chó được truyền vào và modifier có khoảng đệm cho thành phần kết hợp DogHobby().
Column() {
   Row() {
      ...
   }
   DogHobby(
       dog.hobbies,
       modifier = Modifier.padding(
           start = dimensionResource(R.dimen.padding_medium),
           top = dimensionResource(R.dimen.padding_small),
           end = dimensionResource(R.dimen.padding_medium),
           bottom = dimensionResource(R.dimen.padding_medium)
       )
   )
}

Hàm DogItem() hoàn chỉnh sẽ có dạng như sau:

@Composable
fun DogItem(
   dog: Dog,
   modifier: Modifier = Modifier
) {
   var expanded by remember { mutableStateOf(false) }
   Card(
       modifier = modifier
   ) {
       Column() {
           Row(
               modifier = Modifier
                   .fillMaxWidth()
                   .padding(dimensionResource(R.dimen.padding_small))
           ) {
               DogIcon(dog.imageResourceId)
               DogInformation(dog.name, dog.age)
               Spacer(Modifier.weight(1f))
               DogItemButton(
                   expanded = expanded,
                   onClick = { /*TODO*/ },
               )
           }
           DogHobby(
               dog.hobbies, 
               modifier = Modifier.padding(
                   start = dimensionResource(R.dimen.padding_medium),
                   top = dimensionResource(R.dimen.padding_small),
                   end = dimensionResource(R.dimen.padding_medium),
                   bottom = dimensionResource(R.dimen.padding_medium)
               )
           )
       }
   }
}
  1. Xem WoofPreview() trong ngăn Design (Thiết kế). Hãy chú ý đến những sở thích của chú chó.

Bản xem trước Woof với các mục danh sách mở rộng

5. Hiện hoặc ẩn sở thích khi nhấp vào nút

Ứng dụng của bạn đã có nút Expand More (Mở rộng) cho mỗi mục trong danh sách nhưng nút này chưa có chức năng gì! Trong phần này, bạn sẽ thêm lựa chọn ẩn hoặc hiện thông tin về sở thích khi người dùng nhấp vào nút mở rộng.

  1. Trong hàm có khả năng kết hợp DogItem(), trong phương thức gọi hàm DogItemButton(), hãy định nghĩa biểu thức lambda onClick(), thay đổi giá trị trạng thái boolean expanded thành true khi người dùng nhấp vào nút và thay đổi giá trị đó về false nếu người dùng nhấp vào nút này một lần nữa.
DogItemButton(
   expanded = expanded,
   onClick = { expanded = !expanded }
)
  1. Trong hàm DogItem(), hãy gói phương thức gọi hàm DogHobby() bằng một dấu kiểm if trên giá trị boolean expanded.
@Composable
fun DogItem(
   dog: Dog,
   modifier: Modifier = Modifier
) {
   var expanded by remember { mutableStateOf(false) }
   Card(
       ...
   ) {
       Column(
           ...
       ) {
           Row(
               ...
           ) {
               ...
           }
           if (expanded) {
               DogHobby(
                   dog.hobbies, modifier = Modifier.padding(
                       start = dimensionResource(R.dimen.padding_medium),
                       top = dimensionResource(R.dimen.padding_small),
                       end = dimensionResource(R.dimen.padding_medium),
                       bottom = dimensionResource(R.dimen.padding_medium)
                   )
               )
           }
       }
   }
}

Bây giờ, thông tin về sở thích của chú chó chỉ xuất hiện nếu giá trị của expandedtrue.

  1. Bản xem trước có thể cho bạn thấy giao diện người dùng và bạn cũng có thể tương tác với giao diện đó. Để tương tác với bản xem trước giao diện người dùng, hãy di chuột lên trên văn bản WoofPreview trong ngăn Design (Thiết kế), sau đó nhấp vào nút Interactive Mode (Chế độ tương tác) 42379dbe94a7a497.png ở góc trên cùng bên phải của ngăn Design (Thiết kế). Thao tác này sẽ khởi động bản xem trước ở chế độ tương tác.

74e1624d68fb4131.png

  1. Nhấp vào nút mở rộng để tương tác với bản xem trước. Hãy chú ý thông tin về sở thích của chú chó sẽ ẩn và hiện khi bạn nhấp vào nút mở rộng.

Ảnh động mở rộng và thu gọn các mục trong danh sách của Woof

Lưu ý rằng biểu tượng nút mở rộng vẫn giữ nguyên khi mục danh sách được mở rộng. Để cải thiện trải nghiệm người dùng, bạn cần điều chỉnh biểu tượng để ExpandMore cho thấy mũi tên xuống c761ef298c2aea5a.png, còn ExpandLess cho thấy mũi tên lên b380f933be0b6ff4.png.

  1. Trong hàm DogItemButton(), hãy thêm một câu lệnh if để cập nhật giá trị imageVector dựa trên trạng thái expanded như sau:
import androidx.compose.material.icons.filled.ExpandLess

@Composable
private fun DogItemButton(
   ...
) {
   IconButton(onClick = onClick) {
       Icon(
           imageVector = if (expanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
           ...
       )
   }
}

Hãy xem cách bạn đã viết if-else trong đoạn mã trước đó.

if (expanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore

Việc này cũng giống như việc sử dụng dấu ngoặc nhọn { } trong mã sau:

if (expanded) {

`Icons.Filled.ExpandLess`

} else {

`Icons.Filled.ExpandMore`

}

Không bắt buộc phải có dấu ngoặc nhọn nếu có một dòng mã duy nhất cho câu lệnh if-else.

  1. Chạy ứng dụng trên thiết bị hoặc trình mô phỏng hay sử dụng lại chế độ tương tác trong bản xem trước. Lưu ý rằng biểu tượng này thay thế luân phiên giữa các biểu tượng ExpandMore c761ef298c2aea5a.pngExpandLess b380f933be0b6ff4.png.

de5dc4a953f11e65.gif

Bạn đã cập nhật biểu tượng!

Khi mở rộng mục danh sách, bạn có nhận thấy sự thay đổi chiều cao đột ngột không? Thay đổi chiều cao đột ngột không giống như một ứng dụng hoàn hảo. Để giải quyết vấn đề này, tiếp theo bạn sẽ thêm ảnh động vào ứng dụng.

6. Thêm hoạt ảnh

Ảnh động có thể thêm chỉ dẫn trực quan để thông báo cho người dùng về những gì đang diễn ra trong ứng dụng của bạn. Các chỉ dẫn trực quan sẽ đặc biệt hữu ích khi giao diện người dùng thay đổi trạng thái, chẳng hạn như khi tải nội dung mới hoặc khi có các thao tác mới. Các ảnh động cũng có thể giúp giao diện của bạn trở nên tinh tế hơn.

Trong phần này, bạn sẽ thêm ảnh động có hiệu ứng lò xo để tạo sự thay đổi về chiều cao của mục danh sách.

SpringAnimation

Hoạt ảnh vào mùa xuân là một ảnh động dựa trên vật lý do một Lực lượng lò xo điều khiển. Với ảnh động có hiệu ứng lò xo, giá trị và tốc độ chuyển động được tính dựa trên lực của lò xo áp dụng.

Ví dụ: nếu bạn kéo một biểu tượng ứng dụng xung quanh màn hình rồi thả biểu tượng đó ra bằng cách nhấc ngón tay, biểu tượng đó sẽ bật về vị trí ban đầu bằng một lực vô hình.

Ảnh động sau đây cho thấy hiệu ứng mùa xuân. Sau khi thả ngón tay ra khỏi biểu tượng, biểu tượng sẽ bật trở lại, giống một chiếc lò xo.

Hiệu ứng thả lò xo

Hiệu ứng lò xo

Lò xo được dẫn hướng bởi hai thuộc tính sau:

  • Tỷ lệ giảm chấn: Độ nảy của mùa xuân.
  • Độ cứng: Độ cứng của lò xo, tức là tốc độ của lò xo di chuyển đến cuối.

Dưới đây là một số ví dụ về ảnh động có tỷ lệ giảm chấn và độ cứng khác nhau.

Hiệu ứng lò xoĐộ nảy cao

Hiệu ứng lò xoKhông nảy

Độ cứng cao

độ cứng thấp Độ cứng rất thấp

Hãy xem phương thức gọi hàm DogHobby() trong hàm có khả năng kết hợp DogItem(). Thông tin về sở thích của chú chó được bao gồm trong cấu trúc, dựa trên giá trị boolean expanded. Chiều cao của mục trong danh sách sẽ thay đổi, tuỳ thuộc vào việc thông tin về sở thích hiện hay ẩn. Quá trình chuyển đổi hiện đang gây khó chịu. Trong phần này, bạn sẽ sử dụng đối tượng sửa đổi animateContentSize để chuyển đổi suôn sẻ hơn giữa trạng thái mở rộng và trạng thái chưa mở rộng.

// No need to copy over
@Composable
fun DogItem(...) {
  ...
    if (expanded) {
       DogHobby(
          dog.hobbies, 
          modifier = Modifier.padding(
              start = dimensionResource(R.dimen.padding_medium),
              top = dimensionResource(R.dimen.padding_small),
              end = dimensionResource(R.dimen.padding_medium),
              bottom = dimensionResource(R.dimen.padding_medium)
          )
      )
   }
}
  1. Trong MainActivity.kt, trong DogItem(), hãy thêm một tham số modifier vào bố cục Column.
@Composable
fun DogItem(
   dog: Dog, 
   modifier: Modifier = Modifier
) {
   ...
   Card(
       ...
   ) {
       Column(
          modifier = Modifier
       ){
           ...
       }
   }
}
  1. Gắn chuỗi đối tượng sửa đổi với đối tượng sửa đổi animateContentSize để thay đổi kích thước (chiều cao của mục danh sách).
import androidx.compose.animation.animateContentSize

Column(
   modifier = Modifier
       .animateContentSize()
)

Với cách triển khai hiện tại, bạn đang tạo ảnh động cho chiều cao mục danh sách trong ứng dụng của mình. Tuy nhiên, ảnh động này rất tinh tế nên khó có thể nhận biết khi bạn chạy ứng dụng. Để giải quyết vấn đề này, hãy dùng tham số animationSpec tuỳ ý cho phép bạn tuỳ chỉnh ảnh động.

  1. Đối với Woof, ảnh động dễ dàng di chuyển và không nảy. Để làm được việc đó, hãy thêm tham số animationSpec vào phương thức gọi hàm animateContentSize(). Đặt thuộc tính này thành ảnh động lò xo bằng DampingRatioNoBouncy để không tạo độ nảy và tham số StiffnessMedium để lò xo cứng hơn một chút.
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring

Column(
   modifier = Modifier
       .animateContentSize(
           animationSpec = spring(
               dampingRatio = Spring.DampingRatioNoBouncy,
               stiffness = Spring.StiffnessMedium
           )
       )
)
  1. Hãy xem WoofPreview() trong ngăn Design (Thiết kế) rồi sử dụng chế độ tương tác hoặc chạy ứng dụng trên trình mô phỏng hay thiết bị để xem ảnh động lò xo trong thực tế.

c0d0a52463332875.gif

Bạn đã hoàn thành! Hãy thưởng thức ứng dụng tuyệt đẹp của bạn cùng loạt ảnh động.

7. (Không bắt buộc) Thử nghiệm với các ảnh động khác

animate*AsState

Hàm animate*AsState() là một trong những API ảnh động đơn giản nhất trong Compose để tạo ảnh động cho một giá trị duy nhất. Bạn chỉ cung cấp giá trị kết thúc (còn gọi là giá trị đích) và API sẽ bắt đầu tạo ảnh động từ giá trị hiện tại đến giá trị kết thúc được xác định đó.

Ứng dụng Soạn thư cung cấp các hàm animate*AsState() cho Float, Color, Dp, Size, OffsetInt, cùng một số chức năng khác. Bạn có thể dễ dàng hỗ trợ thêm các loại dữ liệu khác bằng cách sử dụng kiểu animateValueAsState() chung.

Hãy thử dùng hàm animateColorAsState() để thay đổi màu khi một mục danh sách được mở rộng.

  1. Trong DogItem(), hãy khai báo màu và uỷ quyền khởi chạy cho hàm animateColorAsState().
import androidx.compose.animation.animateColorAsState

@Composable
fun DogItem(
   dog: Dog,
   modifier: Modifier = Modifier
) {
   var expanded by remember { mutableStateOf(false) }
   val color by animateColorAsState()
   ...
}
  1. Đặt tham số có tên targetValue, tuỳ thuộc vào giá trị boolean expanded. Nếu mục danh sách được mở rộng, hãy đặt mục danh sách thành màu tertiaryContainer. Nếu không, hãy đặt thành màu primaryContainer.
import androidx.compose.animation.animateColorAsState

@Composable
fun DogItem(
   dog: Dog,
   modifier: Modifier = Modifier
) {
   var expanded by remember { mutableStateOf(false) }
   val color by animateColorAsState(
       targetValue = if (expanded) MaterialTheme.colorScheme.tertiaryContainer
       else MaterialTheme.colorScheme.primaryContainer,
   )
   ...
}
  1. Đặt color dưới dạng đối tượng sửa đổi nền thành Column.
@Composable
fun DogItem(
   dog: Dog, 
   modifier: Modifier = Modifier
) {
   ...
   Card(
       ...
   ) {
       Column(
           modifier = Modifier
               .animateContentSize(
                   ...
                   )
               )
               .background(color = color)
       ) {...}
}
  1. Hãy xem hiệu ứng màu thay đổi khi mục danh sách được mở rộng. Các mục danh sách không mở rộng có màu primaryContainer và các mục danh sách mở rộng có màu tertiaryContainer.

Ảnh động animateAsState

8. Lấy mã giải pháp

Để tải xuống mã cho lớp học lập trình đã kết thúc, bạn có thể sử dụng lệnh git này:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git

Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp zip, sau đó giải nén và mở trong Android Studio.

Nếu bạn muốn xem mã giải pháp, hãy xem mã đó trên GitHub.

9. Kết luận

Xin chúc mừng! Bạn đã thêm một nút để ẩn và tiết lộ thông tin về chú chó. Bạn đã nâng cao trải nghiệm người dùng bằng cách sử dụng ảnh động lò xo. Bạn cũng đã tìm hiểu cách sử dụng chế độ tương tác trong ngăn Design (Thiết kế).

Bạn cũng có thể thử một loại Ảnh động soạn thư Jetpack khác. Đừng quên chia sẻ thành quả của mình trên mạng xã hội với #AndroidBasics!

Tìm hiểu thêm