Jetpack Compose cung cấp cách triển khai Material Design 3, bước phát triển tiếp theo của Material Design. Material 3 có các bản cập nhật về giao diệ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ế để nhất quán với phong cách hình ảnh và giao diện người dùng hệ thống mới trên Android 12 trở lên.
Dưới đây, chúng tôi 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 Câu trả lời là 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 Compose Material 3
phần phụ thuộc vào tệp build.gradle
của bạn:
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 hệ thống Material Design, bao gồm màu sắc, kiểu chữ và hình dạng cho ứng dụng của bạn.
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 của bạn sẽ tự động được phản ánh trong các thành phần M3 mà bạn dùng để tạo ứng dụng của bạn.
Jetpack Compose triển khai các khái niệm này bằng M3 MaterialTheme
thành phần kết hợp:
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à dành riêng cho ứng dụng của bạn.
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 phương án trong số này màu liên quan đến bảng sắc độ gồm 13 sắc độ màu mà Material 3 sử dụng thành phần. 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. Tuỳ chỉnh giao diện Material
Công cụ Builder cho phép bạn thực hiện việc này và xuất (không bắt buộc)
Mã giao diện Compose. Các tệp sau đây được tạo:
Color.kt
chứa màu cho giao diện của bạn với tất cả vai trò đã xác định cho 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 về bảng phối màu sáng và tối cũng như ứng dụng chủ đề.
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
cài đặt hệ thống, 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 sắc tuỳ chỉnh từ hình nền của người dùng để áp dụng cho và giao diện người dùng hệ thống. Bảng màu này được dùng làm điểm bắt đầ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 dừng lại ở đó
sang sử dụng ColorScheme
tuỳ chỉnh sáng hoặc tối.
ColorScheme
cung cấp các hàm trình tạo để tạo đèn động hoặc
Bảng phối màu tối:
// 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 }
Mức 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 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 tính năng của thành phần tạo điểm nhấn, làm nổi bật và tạo điểm nhấn.
- Màu chính là màu chủ đạo, dùng cho các thành phần chính như màu nổi bật các nút, trạng thái hoạt động và sắc thái màu của các bề mặt phía trên.
- Màu chính phụ được dùng cho các thành phần ít nổi bật hơn trong giao diện người dùng, chẳng hạn như làm thẻ bộ lọc và mở rộng cơ hội cho biểu thức màu.
- Màu chủ đạo thứ ba được dùng để xác định vai trò của các điểm nhấn tương phản có thể được sử dụng để cân bằng màu chính và màu phụ hoặc làm tăng tính chú ý đến một phần tử.
Thiết kế ứng dụng mẫu Reply (Trả lời) sử dụng màu vùng chứa trên chính 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, ) }
Ở đây, bạn có thể thấy trong ngăn Điều hướng trả lời cách thứ cấp và thứ ba màu vùng chứa được sử dụng tương phản để 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 dòng 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 hiện có
Các lớp TextStyle
và liên quan đến phông chữ – để lập mô hình loại Material 3
quy mô. Hàm khởi tạo Typography
cung cấp các giá trị mặc định cho mỗi kiểu để bạn có thể bỏ qua
bất kỳ tham số 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 Material Design kiểu chữ. Trong ví dụ này, 5 kích thước được chọn cho tập hợp giảm trong khi còn lại sẽ được bỏ qua.
Bạn có thể tuỳ chỉnh kiểu chữ bằng cách thay đổi các giá trị mặc định của TextStyle
và 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 bạn 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 về cách đăng ký 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 thu hút sự 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 các góc vùng chứa, cung cấp nhiều lựa chọn độ bo 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 nhiều hình dạng mang tính biểu đạt trên giao diện người dùng.
Hình dạng có nhiều kích thước:
- Quá nhỏ
- Nhỏ
- Trung bình
- 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 giá trị đó:
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ả các thành phần trong MaterialTheme
hoặc
bạn có thể thực hiện theo từng thành phần.
Áp dụng hình dạng có kích thước trung bình và lớn với các giá trị mặc định:
Card(shape = MaterialTheme.shapes.medium) { /* card content */ } FloatingActionButton( shape = MaterialTheme.shapes.large, onClick = { } ) { /* fab content */ }
Có hai hình dạng khác là RectangleShape
và CircleShape
cũng là một phần
của Compose. Hình chữ nhật không có bán kính đường viền còn hình tròn hiển thị đầy đủ
cạnh tròn:
Card(shape = RectangleShape) { /* card content */ } Card(shape = CircleShape) { /* card content */ }
Các ví dụ dưới đây minh hoạ một số thành phần với giá trị hình dạng mặc định đã áp dụng cho chúng:
Bạn có thể đọc thêm về nguyên tắc của Material về cách đăng ký 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à các yếu tố dựa trên màu sắc kết hợp. Trong M3, có hai cách để tạo điểm nhấn cho 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 on-Surface (vùng hiển thị) màu on-surface-variants từ hệ thống màu sắc mở rộng của M3. Ví dụ: Surface có thể được dùng với on-surface-variant và biến thể vùng hiển thị với trên bề mặt để tạo các mức độ nhấn mạnh 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ữ để có 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 mô hình cách phân biệt vùng chứa với bề mặt — tăng sắc độ độ cao sẽ sử dụng tông màu nổi bật hơn — ngoài 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 Chất liệu 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 — bao gồm tính năng hỗ trợ cho cả độ nâng dùng sắc độ màu 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 tập hợp phong phú các thành phần Material (chẳng hạn như nút, khối, thẻ, thanh điều hướng) đã tuân theo Material Sắp xếp theo chủ đề và giúp bạn tạo ứng dụng Material Design đẹp mắt. Bạn có thể bắt đầu sử dụng với cá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 một thành phần để sử dụng cho nhiều vai trò theo mức độ nhấn mạnh và chú ý.
- Nút thao tác nổi mở rộng cho thao tác nhấn mạnh cao 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 thao tác nhấn mạnh:
Button(onClick = { /*..*/ }) { Text(text = stringResource(id = R.string.view_entry)) }
- Nút văn bản cho một thao tác nhấn 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à các thành phần khác trong Material. Material 3 cung cấp nhiều bộ thành phần như Nút (Button), Ứng dụng (App) thanh, thành phần Điều hướng được thiết kế đặc biệt cho những mục đích sử dụng khác nhau ốp lưng và kích thước màn hình.
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 thao tác, tuỳ thuộc vào 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 nhóm trở xuống
điểm đến:
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 trung bình ở
chế độ ngang. Công cụ này mang đến sự công thái học 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 giao diện mặc định để mang lại trải nghiệm sống động cho người dùng kích thước thiết bị của bạn.
NavigationDrawer
được dùng cho các 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 tuỳ chọn điều hướng giúp nâng cao trải nghiệm người dùng, sự thoải mái và phạm vi tiếp cận. Bạn có thể tìm hiểu thêm về thành phần điều hướng Material trong Lớp học lập trình thích ứng Compose.
Tuỳ chỉnh giao diện của thành phần
M3 khuyến khích hoạt động cá nhân hoá và tạo sự linh hoạt. Tất cả các thành phần đều có giá trị mặc định được áp dụng cho chúng nhưng hiển thị các API linh hoạt để tuỳ chỉnh màu nếu là bắt buộc.
Hầu hết các thành phần, chẳng hạn như thẻ và nút, đều cung cấp một đối tượng mặc định hiển thị màu sắc và giao diện độ cao có thể được 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.
Hiệu ứng 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 RippleDrawable trên nền tảng nâng cao Android nên hiệu ứng gợn sóng lấp lánh có sẵn trên Android 12 trở lên đối với mọi Material thành phần.
Cuộn xuống cuối cùng (overscroll)
Giờ đây, thao tác cuộn quá mức sẽ sử dụng hiệu ứng kéo giãn ở cạnh của vùng chứa cuộn.
Tính năng cuộn quá mức kéo giãn được bật theo mặc định trong các thành phần kết hợp vùng chứa cuộn – đối với
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 hỗ trợ tiếp cận tích hợp sẵn trong thành phần Material được thiết kế để cung cấp nền tảng cho thiết kế sản phẩm toàn diện. Việc tìm hiểu về khả năng hỗ trợ tiếp cậ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 dùng thị lực, mù, suy giảm thính lực, suy giảm nhận thức, vận động khuyết tật hoặc khuyết tật về tình trạng (chẳng hạn như gãy tay).
Hỗ trợ tiếp cận bằng màu sắc
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à yếu tố quan trọng để giúp mọi bảng phối màu dễ tiếp cận theo mặc định.
Hệ thống màu của Material cung cấp thông tin đo lường và giá trị tông màu tiêu chuẩn có thể để đáp ứng tỷ lệ tương phản dễ tiếp cận.
Tất cả thành phần Material và giao diện động đều đã sử dụng vai trò của màu sắc nêu trên từ một tập hợp bảng sắc độ, được chọn để đáp ứng khả năng hỗ trợ tiếp cận các yêu cầu liên quan. Tuy nhiên, nếu bạn đang tuỳ chỉnh các thành phần, hãy nhớ sử dụng vai trò của màu sắc thích hợp và tránh việc trùng khớp.
Dùng bảng màu on-primary (màu nền của màu chính) trên màu chính và vùng chứa on-primary (màu nền của màu chính) ở trên chính-vùng chứa, cũng như tương tự 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 với người dùng.
Việc sử dụng vùng chứa thứ ba ở trên vùng chứa chính sẽ mang lại cho người dùng nút tương phản:
// ✅ 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 cho kiểu chữ
Thang loại M3 cập nhật các giá trị và đoạn đường dốc loại tĩnh để cung cấp nhưng khung linh động của các danh mục kích thước có thể mở rộng trên các thiết bị.
Ví dụ: trong M3, Display Small có thể được gán các giá trị khác nhau tuỳ thuộc vào dựa trên bối 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 đưa ra hướng dẫn về bố cục thích ứng và thiết bị có thể gập lại để giúp bạn tạo ứng dụng dễ tiếp cận và cải thiện cảm giác thoải mái khi người dùng cầm thiết bị lớn.
Material cung cấp nhiều loại thao tác để giúp bạn mang lại trải nghiệm tốt hơn cho người dùng trên các thiết bị lớn.
Bạn có thể tìm hiểu thêm về nguyên tắc về chất lượng đối với ứng dụng có màn hình lớn của Android và hãy xem mẫu Reply của chúng tôi để biết thiết kế thích ứng và dễ 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, hãy xem các nội dung sau tài nguyên:
Ứ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