Jetpack Compose cung cấp cách triển khai Material Design 3, phiên bản cải tiến tiếp theo của Material Design. Material 3 có khả năng tuỳ chỉnh giao diện cập nhật, thành phần và các tính năng cá nhân hoá Material You như màu động, đồng thời được thiết kế để phù hợp với phong cách hình ảnh mới và giao diện người dùng hệ thống trên Android 12 trở lên.
Dưới đây là ví dụ minh hoạ cách triển khai Material Design 3, lấy ứng dụng mẫu Reply (Trả lời) làm ví dụ. Mẫu Reply (Trả lời) hoàn toàn dựa trên Material Design 3.
Phần phụ thuộc
Để bắt đầu sử dụng Material 3 trong ứng dụng Compose, hãy thêm phần phụ thuộc Compose Material 3 vào tệp build.gradle
:
implementation "androidx.compose.material3:material3:$material3_version"
Sau khi thêm phần phụ thuộc, bạn có thể bắt đầu thêm các hệ thống Material Design, bao gồm màu sắc, kiểu chữ và hình dạng vào ứng dụng của mình.
API thử nghiệm
Một số API của M3 được coi là thử nghiệm. Trong những trường hợp như vậy, bạn cần chọn sử dụng ở cấp độ hàm hoặc tệp bằng cách sử dụng chú thích ExperimentalMaterial3Api
:
// import androidx.compose.material3.ExperimentalMaterial3Api @OptIn(ExperimentalMaterial3Api::class) @Composable fun AppComposable() { // M3 composables }
Tuỳ chỉnh giao diện Material
Giao diện M3 chứa các hệ thống con sau: bảng phối màu, kiểu chữ và hình dạng. Khi bạn tuỳ chỉnh các giá trị này, thay đổi sẽ tự động phản ánh trong các thành phần M3 mà bạn sử dụng để xây dựng ứng dụng.
Jetpack Compose triển khai các khái niệm này bằng thành phần kết hợp MaterialTheme
của M3:
MaterialTheme( colorScheme = /* ... typography = /* ... shapes = /* ... ) { // M3 app content }
Để tạo giao diện cho nội dung ứng dụng, hãy xác định bảng phối màu, kiểu chữ và hình dạng dành riêng cho ứng dụng.
Bảng phối màu
Nền tảng của bảng phối màu là bộ 5 màu chủ đạo. Mỗi màu trong số này liên quan đến một bảng sắc độ gồm 13 tông màu, được các thành phần Material 3 sử dụng. Ví dụ: đây là bảng phối màu cho giao diện sáng của Trả lời:
Đọc thêm về Bảng phối màu và vai trò của màu.
Tạo bảng phối màu
Mặc dù bạn có thể tạo ColorScheme
tuỳ chỉnh theo cách thủ công, việc tạo một bảng phối màu bằng màu gốc trong thương hiệu thường sẽ dễ dàng hơn. Công cụ tạo giao diện Material giúp bạn làm điều này cùng với việc xuất mã giao diện Compose (không bắt buộc). Các tệp sau đây sẽ được tạo:
Color.kt
chứa màu cho giao diện của bạn, đồng thời xác định tất cả vai trò của màu sắc trên cả giao diện sáng lẫn giao diện tối.
val md_theme_light_primary = Color(0xFF476810) val md_theme_light_onPrimary = Color(0xFFFFFFFF) val md_theme_light_primaryContainer = Color(0xFFC7F089) // .. // .. val md_theme_dark_primary = Color(0xFFACD370) val md_theme_dark_onPrimary = Color(0xFF213600) val md_theme_dark_primaryContainer = Color(0xFF324F00) // .. // ..
Theme.kt
chứa thông tin thiết lập cho bảng phối màu sáng và tối cũng như giao diện của ứng dụng.
private val LightColorScheme = lightColorScheme( primary = md_theme_light_primary, onPrimary = md_theme_light_onPrimary, primaryContainer = md_theme_light_primaryContainer, // .. ) private val DarkColorScheme = darkColorScheme( primary = md_theme_dark_primary, onPrimary = md_theme_dark_onPrimary, primaryContainer = md_theme_dark_primaryContainer, // .. ) @Composable fun ReplyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val colorScheme = if (!darkTheme) { LightColorScheme } else { DarkColorScheme } MaterialTheme( colorScheme = colorScheme, content = content ) }
Để hỗ trợ các giao diện sáng và tối, hãy dùng isSystemInDarkTheme()
. Dựa trên chế độ cài đặt hệ thống, hãy xác định bảng phối màu sẽ sử dụng: sáng hoặc tối.
Bảng phối màu linh động
Màu động là thành phần quan trọng của Material You, trong đó thuật toán lấy màu tuỳ chỉnh từ hình nền của người dùng để áp dụng cho ứng dụng và giao diện người dùng hệ thống. Bảng màu này được dùng làm điểm khởi đầu để tạo bảng phối màu sáng và tối.
Màu động hiện có trên phiên bản Android 12 trở lên. Nếu màu linh động có sẵn, bạn có thể thiết lập ColorScheme
linh động. Nếu không thể, bạn nên quay lại sử dụng ColorScheme
sáng hoặc tối tuỳ chỉnh.
ColorScheme
cung cấp các hàm tạo để tạo bảng phối màu sáng hoặc tối động:
// Dynamic color is available on Android 12+ val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S val colors = when { dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current) dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current) darkTheme -> DarkColorScheme else -> LightColorScheme }
Sử dụng màu sắc
Bạn có thể truy cập vào màu giao diện Material trong ứng dụng của mình thông qua MaterialTheme.colorScheme
:
Text( text = "Hello theming", color = MaterialTheme.colorScheme.primary )
Mỗi vai trò của màu sắc có thể được sử dụng ở nhiều nơi, tuỳ thuộc vào trạng thái, làm nổi bật và tạo điểm nhất cho thành phần.
- Màu chính là màu chủ đạo, được dùng cho các thành phần chính như các nút làm nổi bật, trạng thái đang hoạt động và sắc thái màu của các bề mặt nâng cao.
- Màu khoá phụ được dùng cho các thành phần ít nổi bật hơn trên giao diện người dùng (chẳng hạn như thẻ bộ lọc), đồng thời mở rộng cơ hội cho biểu thức màu.
- Màu khoá trung gian được dùng để lấy ra vai trò của các điểm nhấn tương phản có thể dùng để cân bằng màu chính và màu phụ hoặc giúp tăng mức độ chú ý cho một thành phần.
Thiết kế ứng dụng mẫu Reply (Trả lời) dùng màu trên vùng chứa chính ở trên vùng chứa chính để làm nổi bật mục đã chọn.
Card( colors = CardDefaults.cardColors( containerColor = if (isSelected) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceVariant ) ) { Text( text = "Dinner club", style = MaterialTheme.typography.bodyLarge, color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface, ) }
Tại đây, bạn có thể thấy trong ngăn Điều hướng trả lời cách sử dụng màu vùng chứa cấp hai và màu cấp 3 tương phản với nhau để tạo điểm nhấn và tạo điểm nhấn.
Kiểu chữ
Material Design 3 xác định tỷ lệ cỡ chữ, bao gồm cả các kiểu văn bản đã được điều chỉnh từ Material Design 2. Cách đặt tên và phân nhóm đã được đơn giản hoá thành: hiển thị, dòng tiêu đề, tiêu đề, nội dung và nhãn, với kích thước lớn, trung bình và nhỏ cho mỗi nhóm.
M3 | Kích thước phông chữ/chiều cao mặc định |
displayLarge |
Roboto 57/64 |
displayMedium |
Roboto 45/52 |
displaySmall |
Roboto 36/44 |
headlineLarge |
Roboto 32/40 |
headlineMedium |
Roboto 28/36 |
headlineSmall |
Roboto 24/32 |
titleLarge |
New- Roboto Medium 22/28 |
titleMedium |
Roboto Medium 16/24 |
titleSmall |
Roboto Medium 14/20 |
bodyLarge |
Roboto 16/24 |
bodyMedium |
Roboto 14/20 |
bodySmall |
Roboto 12/16 |
labelLarge |
Roboto Medium 14/20 |
labelMedium |
Roboto Medium 12/16 |
labelSmall |
New Roboto Medium, 11/16 |
Xác định kiểu chữ
Compose cung cấp lớp Typography
của M3 – cùng với các lớp TextStyle
và liên quan đến phông chữ hiện có – để lập mô hình kiểu chữ trong Material 3. Hàm khởi tạo Typography
cung cấp các kiểu mặc định tương ứng với từng kiểu để bạn có thể bỏ qua bất kỳ kiểu nào bạn không muốn tuỳ chỉnh:
val replyTypography = Typography( titleLarge = TextStyle( fontWeight = FontWeight.SemiBold, fontSize = 22.sp, lineHeight = 28.sp, letterSpacing = 0.sp ), titleMedium = TextStyle( fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp ), // .. ) // ..
Sản phẩm của bạn có thể sẽ không dùng đến toàn bộ 15 kiểu mặc định trong tỷ lệ kiểu chữ trên Material Design. Trong ví dụ này, 5 kích thước được chọn để giảm kích thước trong khi bỏ qua các kích thước còn lại.
Bạn có thể tuỳ chỉnh kiểu chữ bằng cách thay đổi giá trị mặc định của các thuộc tính TextStyle
và các thuộc tính liên quan đến phông chữ như fontFamily
và letterSpacing
.
bodyLarge = TextStyle( fontWeight = FontWeight.Normal, fontFamily = FontFamily.SansSerif, fontStyle = FontStyle.Italic, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp, baselineShift = BaselineShift.Subscript ),
Sau khi xác định Typography
, hãy truyền nó vào MaterialTheme
của M3:
MaterialTheme( typography = replyTypography, ) { // M3 app Content }
Sử dụng kiểu văn bản
Bạn có thể truy xuất kiểu chữ được cung cấp cho thành phần kết hợp MaterialTheme
của M3 bằng cách sử dụng MaterialTheme.typography
:
Text( text = "Hello M3 theming", style = MaterialTheme.typography.titleLarge ) Text( text = "you are learning typography", style = MaterialTheme.typography.bodyMedium )
Bạn có thể đọc thêm về nguyên tắc của Material liên quan đến việc áp dụng kiểu chữ.
Hình dạng
Vùng hiển thị của Material có thể hiển thị ở nhiều hình dạng. Hình dạng thường chi phối sự chú ý, cách xác định các thành phần, trạng thái giao tiếp và thể hiện thương hiệu.
Tỷ lệ hình dạng xác định kiểu của góc vùng chứa, có nhiều độ tròn từ hình vuông đến hình tròn hoàn toàn.
Xác định hình dạng
Compose cung cấp cho lớp Shapes
của M3 các tham số mở rộng để hỗ trợ hình dạng mới trong M3. Tỷ lệ hình dạng trong M3 giống với tỷ lệ cỡ chữ, cho phép hiển thị nhiều hình dạng để thể hiện trên giao diện người dùng.
Hình dạng có nhiều kích thước khác nhau:
- Quá nhỏ
- Nhỏ
- Medium
- Lớn
- Rất lớn
Theo mặc định, mỗi hình dạng có một giá trị mặc định, nhưng bạn có thể ghi đè các hình dạng đó:
val replyShapes = Shapes( extraSmall = RoundedCornerShape(4.dp), small = RoundedCornerShape(8.dp), medium = RoundedCornerShape(12.dp), large = RoundedCornerShape(16.dp), extraLarge = RoundedCornerShape(24.dp) )
Sau khi xác định Shapes
, bạn có thể truyền nó đến MaterialTheme
của M3:
MaterialTheme( shapes = replyShapes, ) { // M3 app Content }
Sử dụng hình dạng
Bạn có thể tuỳ chỉnh tỷ lệ hình dạng cho tất cả thành phần trong MaterialTheme
hoặc có thể tuỳ chỉnh cho từng thành phần.
Áp dụng hình dạng có kích thước trung bình và lớn bằng các giá trị mặc định:
Card(shape = MaterialTheme.shapes.medium) { /* card content */ } FloatingActionButton( shape = MaterialTheme.shapes.large, onClick = { } ) { /* fab content */ }
Ngoài ra còn có hai hình dạng khác là RectangleShape
và CircleShape
. Chúng cũng là một phần của Compose. Hình chữ nhật không có bán kính bo góc còn hình tròn hiển thị các cạnh tròn:
Card(shape = RectangleShape) { /* card content */ } Card(shape = CircleShape) { /* card content */ }
Ví dụ bên dưới minh hoạ một số thành phần có giá trị hình dạng mặc định được áp dụng:
Bạn có thể đọc thêm về nguyên tắc của Material liên quan đến việc áp dụng hình dạng.
Điểm nhấn
Điểm nhấn trong M3 được cung cấp bằng cách sử dụng các biến thể màu sắc và sự kết hợp dựa trên màu sắc. Trong M3, có hai cách để làm nổi bật giao diện người dùng:
- Sử dụng surface (vùng hiển thị), surface-variant (biến thể của vùng hiển thị) cùng với màu on-surface (màu nền cho vùng hiển thị) trong hệ thống màu sắc mở rộng của M3. Ví dụ: có thể dùng vùng hiển thị với màu on-surface-variant và biến thể vùng hiển thị có thể dùng với màu on-surface để tạo các mức độ nổi bật khác nhau.
- Sử dụng nhiều độ đậm phông chữ cho văn bản. Ở trên, bạn đã thấy rằng bạn có thể cung cấp trọng số tuỳ chỉnh cho kiểu chữ để thể hiện mức độ nhấn khác nhau.
bodyLarge = TextStyle( fontWeight = FontWeight.Bold ), bodyMedium = TextStyle( fontWeight = FontWeight.Normal )
Độ nâng
Material 3 thể hiện độ nâng (elevation) chủ yếu bằng cách sử dụng lớp phủ sắc độ màu. Đây là một cách mới để phân biệt vùng chứa với bề mặt — sử dụng tông màu nổi bật để tăng độ nâng màu (bên cạnh hiệu ứng đổ bóng).
Lớp phủ độ nâng trong giao diện tối cũng đã thay đổi thành lớp phủ sắc độ màu trong Material 3. Màu của lớp phủ lấy dựa trên màu chính.
Surface (vùng hiển thị) của M3 — thành phần kết hợp sao lưu là yếu tố cơ bản của hầu hết các thành phần trong M3 — có độ nâng dựa trên sắc độ và đổ bóng:
Surface( modifier = Modifier, tonalElevation = /*... shadowElevation = /*... ) { Column(content = content) }
Thành phần Material
Material Design đi kèm với một bộ các thành phần Material phong phú (chẳng hạn như nút, khối, thẻ, thanh điều hướng) đã tuân theo tính năng Tuỳ chỉnh giao diện Material và giúp bạn tạo các ứng dụng Material Design đẹp mắt. Bạn có thể bắt đầu sử dụng các thành phần có thuộc tính mặc định ngay từ đầu.
Button(onClick = { /*..*/ }) { Text(text = "My Button") }
M3 cung cấp nhiều phiên bản của cùng các thành phần được sử dụng trong nhiều vai trò, tuỳ theo mức độ nhấn mạnh và chú ý.
- Nút hành động nổi mở rộng dành cho thao tác nhấn mạnh nhất:
ExtendedFloatingActionButton( onClick = { /*..*/ }, modifier = Modifier ) { Icon( imageVector = Icons.Default.Edit, contentDescription = stringResource(id = R.string.edit), ) Text( text = stringResource(id = R.string.add_entry), ) }
- Nút được tô màu nền cho một thao tác nhấn mạnh mức độ nhấn mạnh:
Button(onClick = { /*..*/ }) { Text(text = stringResource(id = R.string.view_entry)) }
- Nút văn bản cho thao tác nhấn mạnh thấp:
TextButton(onClick = { /*..*/ }) { Text(text = stringResource(id = R.string.replated_articles)) }
Bạn có thể đọc thêm về các nút và thành phần khác của Material. Material 3 cung cấp nhiều bộ thành phần, chẳng hạn như Nút, Thanh ứng dụng, thành phần Điều hướng được thiết kế riêng cho các trường hợp sử dụng và kích thước màn hình khác nhau.
Thành phần điều hướng
Material cũng cung cấp một số thành phần điều hướng giúp bạn triển khai tính năng điều hướng, tuỳ thuộc vào nhiều kích thước và trạng thái màn hình.
NavigationBar
dùng cho các thiết bị nhỏ gọn khi bạn muốn nhắm đến 5 đích đến trở xuống:
NavigationBar(modifier = Modifier.fillMaxWidth()) { Destinations.entries.forEach { replyDestination -> NavigationBarItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { } ) } }
NavigationRail
được dùng cho máy tính bảng hoặc điện thoại có kích thước từ nhỏ đến vừa ở chế độ ngang. Hộp cát về quyền riêng tư mang lại sự thoải mái cho người dùng và cải thiện trải nghiệm người dùng cho các thiết bị đó.
NavigationRail( modifier = Modifier.fillMaxHeight(), ) { Destinations.entries.forEach { replyDestination -> NavigationRailItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { } ) } }
Trả lời bằng cả hai tính năng này trong giao diện mặc định để cung cấp trải nghiệm người dùng sống động cho mọi kích thước thiết bị.
NavigationDrawer
được sử dụng cho những máy tính bảng có kích thước từ trung bình đến lớn mà bạn có đủ không gian để hiển thị chi tiết. Bạn có thể sử dụng cả PermanentNavigationDrawer
hoặc ModalNavigationDrawer
cùng với NavigationRail
.
PermanentNavigationDrawer(modifier = Modifier.fillMaxHeight(), drawerContent = { Destinations.entries.forEach { replyDestination -> NavigationRailItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { }, label = { } ) } }) { }
Các lựa chọn điều hướng giúp nâng cao trải nghiệm người dùng, tính công thái học và phạm vi tiếp cận. Bạn có thể tìm hiểu thêm về các thành phần điều hướng Material trong Lớp học lập trình về tính thích ứng của Compose.
Tuỳ chỉnh giao diện của một thành phần
M3 khuyến khích cá nhân hoá và tính linh hoạt. Tất cả thành phần đều được áp dụng màu mặc định nhưng hiển thị các API linh hoạt để tuỳ chỉnh màu sắc nếu cần.
Hầu hết các thành phần (như thẻ và nút) đều cung cấp một đối tượng mặc định hiển thị giao diện màu và độ nâng có thể sửa đổi để tuỳ chỉnh thành phần của bạn:
val customCardColors = CardDefaults.cardColors( contentColor = MaterialTheme.colorScheme.primary, containerColor = MaterialTheme.colorScheme.primaryContainer, disabledContentColor = MaterialTheme.colorScheme.surface, disabledContainerColor = MaterialTheme.colorScheme.onSurface, ) val customCardElevation = CardDefaults.cardElevation( defaultElevation = 8.dp, pressedElevation = 2.dp, focusedElevation = 4.dp ) Card( colors = customCardColors, elevation = customCardElevation ) { // m3 card content }
Bạn có thể đọc thêm về cách tuỳ chỉnh Material 3.
Giao diện người dùng hệ thống
Một số khía cạnh của Material You bắt nguồn từ kiểu hình ảnh và giao diện người dùng hệ thống mới trên Android 12 trở lên. Hai khía cạnh chính có thay đổi là hiệu ứng gợn sóng và cuộn quá mức. Bạn không cần làm gì thêm để triển khai những thay đổi này.
Gợn sóng
Hiệu ứng gợn sóng hiện sử dụng ánh sáng lấp lánh để chiếu sáng các bề mặt khi nhấn. Compose Material Ripple sử dụng nền tảng RippleDrawable nâng cao trên Android, vì vậy, hiệu ứng gợn sóng lấp lánh có sẵn trên Android 12 trở lên cho tất cả các thành phần Material.
Cuộn xuống cuối cùng (overscroll)
Cuộn quá mức hiện sử dụng hiệu ứng kéo giãn ở cạnh của vùng chứa cuộn.
Theo mặc định, tính năng cuộn quá mức được bật trong các thành phần kết hợp vùng chứa cuộn (ví dụ: LazyColumn
, LazyRow
và LazyVerticalGrid
) trong Compose Foundation 1.1.0 trở lên, bất kể cấp độ API.
Hỗ trợ tiếp cận
Các tiêu chuẩn về khả năng hỗ trợ tiếp cận được tích hợp trong các thành phần Material được thiết kế nhằm cung cấp nền tảng cho thiết kế sản phẩm bao quát. Khi hiểu rõ khả năng hỗ trợ tiếp cận của sản phẩm, bạn có thể nâng cao khả năng hữu dụng cho tất cả người dùng, bao gồm cả những người có thị lực kém, khiếm thị, khiếm thính, suy giảm nhận thức, suy giảm vận động hoặc khuyết tật tình huống (chẳng hạn như gãy tay).
Hỗ trợ tiếp cận màu
Màu động được thiết kế để đáp ứng các tiêu chuẩn hỗ trợ tiếp cận về độ tương phản màu. Hệ thống bảng sắc độ là rất quan trọng để làm cho mọi bảng phối màu có thể truy cập được theo mặc định.
Hệ thống màu của Material cung cấp các giá trị tông màu và thông tin đo lường chuẩn có thể dùng để đáp ứng tỷ lệ tương phản dễ tiếp cận.
Tất cả các thành phần Material và tuỳ chỉnh giao diện động đã sử dụng các vai trò màu nêu trên từ một tập hợp bảng sắc độ, được chọn để đáp ứng các yêu cầu về hỗ trợ tiếp cận. Tuy nhiên, nếu bạn đang tuỳ chỉnh các thành phần, hãy đảm bảo sử dụng các vai trò màu sắc phù hợp và tránh việc không khớp.
Dùng màu on-primary (màu nền của màu chính) và màu on-primary-container (màu nền của màu chính cho vùng chứa) trên màu chính cho vùng chứa. Tương tự, hãy phối màu cho các màu nhấn và màu trung tính khác để cung cấp độ tương phản dễ tiếp cận cho người dùng.
Việc sử dụng vùng chứa cấp ba phía trên cùng sẽ khiến người dùng có nút tương phản kém:
// ✅ Button with sufficient contrast ratio Button( onClick = { }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.primary, contentColor = MaterialTheme.colorScheme.onPrimary ) ) { } // ❌ Button with poor contrast ratio Button( onClick = { }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.tertiaryContainer, contentColor = MaterialTheme.colorScheme.primaryContainer ) ) { }
Hỗ trợ tiếp cận về kiểu chữ
Tỷ lệ kiểu chữ M3 cập nhật đường dốc và giá trị kiểu tĩnh để cung cấp một khung đơn giản nhưng linh động cho các danh mục kích thước mở rộng được trên các thiết bị.
Ví dụ: trong M3, Display Small có thể được chỉ định các giá trị khác nhau tuỳ thuộc vào ngữ cảnh của thiết bị, chẳng hạn như điện thoại hoặc máy tính bảng.
Màn hình lớn
Material cung cấp hướng dẫn về bố cục thích ứng và thiết bị có thể gập lại để giúp người dùng dễ tiếp cận ứng dụng của bạn, cũng như cải thiện hiệu quả của việc người dùng cầm thiết bị lớn.
Material cung cấp nhiều loại điều hướng để giúp bạn mang lại trải nghiệm người dùng tốt hơn cho các thiết bị lớn.
Bạn có thể tìm hiểu thêm về các nguyên tắc về chất lượng ứng dụng cho màn hình lớn của Android và xem mẫu Trả lời của chúng tôi để có được thiết kế thích ứng và hỗ trợ tiếp cận.
Tìm hiểu thêm
Để tìm hiểu thêm về tính năng Tuỳ chỉnh giao diện Material trong Compose, vui lòng xem các tài nguyên sau:
Ứng dụng mẫu
Tài liệu
Tài liệu tham khảo API và mã nguồn
Video
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Di chuyển từ Material 2 sang Material 3 trong Compose
- Material Design 2 trong Compose
- Hệ thống thiết kế tuỳ chỉnh trong Compose