Jetpack Compose giúp việc thiết kế và xây dựng giao diện người dùng cho ứng dụng trở nên dễ dàng hơn nhiều. Compose chuyển đổi trạng thái thành các thành phần trên giao diện người dùng, thông qua:
- Cấu tạo của các thành phần
- Bố cục của các thành phần
- Bản vẽ các thành phần
Tài liệu này tập trung vào bố cục của các thành phần, giải thích một số khối xây dựng mà Compose đưa ra để giúp sắp đặt bố cục các thành phần trên giao diện người dùng.
Mục tiêu của các bố cục trong Compose
Việc triển khai hệ thống bố cục trong Jetpack Compose có hai mục tiêu chính:
- Hiệu suất cao
- Khả năng viết các bố cục tuỳ chỉnh một cách dễ dàng
Kiến thức cơ bản về hàm có khả năng kết hợp
Hàm có khả năng kết hợp là khối xây dựng cơ bản trong Compose. Hàm
có khả năng kết hợp là một hàm chèn Unit
mô tả một số phần trên giao diện người dùng. Hàm
sử dụng một số dữ liệu đầu vào và tạo nội dung hiển thị trên màn hình. Để biết thêm
thông tin về các thành phần kết hợp, hãy xem tài liệu Mô hình
tư duy của Compose.
Một hàm có khả năng kết hợp có thể chuyển phát nhiều phần tử trên giao diện người dùng. Tuy nhiên, nếu bạn không đưa ra cách sắp xếp, thì Compose có thể sắp xếp các thành phần theo cách mà bạn không muốn. Ví dụ: mã này tạo ra hai thành phần văn bản:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
Nếu bạn không hướng dẫn cách sắp xếp các thành phần này, thì công cụ Compose sẽ xếp chồng các thành phần văn bản lên nhau, khiến cho chúng không thể đọc được:
Compose cung cấp một tập hợp các bố cục sẵn sàng sử dụng để giúp bạn sắp xếp các thành phần trên giao diện người dùng và giúp bạn dễ dàng xác định các bố cục của riêng mình, ở mức độ chuyên biệt cao hơn.
Các thành phần của bố cục tiêu chuẩn
Trong nhiều trường hợp, bạn chỉ cần sử dụng Các thành phần của bố cục tiêu chuẩn trong Compose.
Hãy dùng
Column
để đặt các mục theo chiều dọc trên màn hình.
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
Tương tự, hãy dùng
Row
để đặt các mục theo chiều ngang trên màn hình. Cả hai mã Column
và Row
đều hỗ trợ
định cấu hình căn chỉnh các thành phần có trong mã.
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
Sử dụng Box
để xếp các thành phần chồng lên nhau. Box
cũng hỗ trợ định cấu hình căn chỉnh cụ thể các thành phần có trong mã.
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
Thông thường, các khối xây dựng này là tất cả những gì bạn cần. Bạn có thể viết hàm có khả năng kết hợp của riêng mình để kết hợp các bố cục này vào một bố cục chi tiết hơn phù hợp với ứng dụng của bạn.
Để đặt vị trí bố cục con trong Row
, hãy đặt các đối số horizontalArrangement
và
verticalAlignment
. Đối với Column
, hãy đặt các đối số verticalArrangement
và
horizontalAlignment
:
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
Mô hình bố cục
Trong mô hình bố cục, cây giao diện người dùng được sắp xếp chỉ trong một luồng. Trước tiên, mỗi nút được yêu cầu tự đo lường, sau đó đo lường định kỳ bất cứ thành phần con cháu nào, chuyển các giới hạn kích thước xuống dọc theo cây cho các thành phần con cháu. Sau đó, cần định kích thước và đặt các nút lá, rồi các kích cỡ đã được xác định cùng các câu lệnh hướng dẫn vị trí được chuyển trở lại cây.
Tóm lại, cần đo lường các thành phần mẹ trước các thành phần con cháu, nhưng việc định kích thước và đặt các thành phần mẹ lại diễn ra sau các thành phần con cháu.
Hãy xem xét hàm SearchResult
sau.
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
Hàm này tạo cây giao diện người dùng sau đây.
SearchResult
Row
Image
Column
Text
Text
Trong ví dụ SearchResult
, bố cục cây giao diện người dùng tuân theo thứ tự sau:
- Câu lệnh yêu cầu đo lường nút gốc
Row
. - Nút gốc
Row
yêu cầu nút con cháu đầu tiên của nó,Image
, đo lường. Image
là một nút lá (nút không có nút con cháu), vì vậy nút này báo cáo kích thước và trả về các câu lệnh hướng dẫn vị trí.- Nút gốc
Row
yêu cầu nút con cháu thứ hai của nó,Column
, đo lường. - Nút
Column
yêu cầu nút con cháu đầu tiên của nó,Text
, đo lường. - Nút
Text
đầu tiên là một nút lá. Nút lá chỉ báo cáo kích thước và trả về câu lệnh hướng dẫn vị trí. - Nút
Column
yêu cầu nút con cháuText
thứ hai của nó đo lường. - Nút
Text
thứ hai là một nút lá, vì vậy nút này báo cáo kích thước và trả về câu lệnh hướng dẫn vị trí. - Hiện tại, nút
Column
đã đo lường xong, đã định kích thước và đặt các nút con cháu của nó, nút này có thể xác định kích thước và vị trí của riêng mình. - Hiện tại, nút gốc
Row
đã đo lường xong, đã định kích thước và đặt các nút con cháu của nó, nút này có thể xác định kích thước và vị trí của riêng mình.
Hiệu suất
Compose đạt được hiệu suất cao bằng cách đo lường nút con cháu một lần duy nhất. Chế độ đo lường một luồng tốt cho hiệu suất, cho phép công cụ Compose xử lý sâu các cây giao diện người dùng một cách hiệu quả. Nếu một thành phần đo lường thành phần con cháu của nó hai lần và thành phần con cháu đó đo lường từng thành phần con cháu của nó hai lần và cứ tiếp tục như vậy, thì một lần thử duy nhất để tạo ra toàn bộ Giao diện người dùng sẽ phải thực hiện rất nhiều việc, khiến ứng dụng của bạn khó duy trì hoạt động.
Nếu bố cục của bạn cần nhiều lần đo lường vì một lý do nào đó, Compose có một hệ thống đặc biệt, phép đo lường hàm nội tại. Bạn có thể đọc thêm về tính năng này ở phần Phép đo lường hàm nội tại trong bố cục Compose.
Vì việc đo lường và vị trí là các giai đoạn phụ riêng biệt của luồng bố cục, nên các thay đổi chỉ ảnh hưởng đến vị trí của các mục mà không ảnh hưởng đến hoạt động đo lường, đều có thể được thực hiện riêng biệt.
Sử dụng đối tượng sửa đổi trong bố cục của bạn
Như đã đề cập ở phần các đối tượng sửa đổi trong Compose, bạn có thể sử dụng đối tượng sửa đổi để trang trí hoặc bổ sung các thành phần kết hợp của bạn. Các đối tượng sửa đổi là thành phần cần thiết để tuỳ chỉnh bố cục của bạn. Ví dụ: ở đây chúng tôi liên kết một số đối tượng sửa đổi để tuỳ chỉnh ArtistCard
:
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
Trong mã trên, hãy chú ý đến các đối tượng sửa đổi có chức năng khác nhau được sử dụng cùng nhau.
clickable
tạo một phản ứng kết hợp với thông tin do người dùng nhập và hiển thị một hiệu ứng gợn sóng.padding
đặt khoảng trống quanh một thành phần.fillMaxWidth
làm cho thành phần kết hợp lấp đầy chiều rộng tối đa mà thành phần mẹ đã cấp cho nó.size()
xác định chiều rộng và chiều cao ưu tiên của một thành phần.
Bố cục có thể cuộn
Hãy tìm hiểu thêm về bố cục có thể cuộn trong tài liệu về hành động của Compose.
Để xem các danh sách và danh sách tải lười, hãy xem tài liệu về hành động của Compose.
Bố cục thích ứng
Bạn nên thiết kế bố cục với các hướng màn hình khác nhau và kích thước kiểu dáng. Compose cung cấp một số cơ chế để hỗ trợ điều chỉnh các bố cục có thể kết hợp của bạn với nhiều cấu hình màn hình khác nhau.
Giới hạn
Để biết các giới hạn từ thành phần mẹ và thiết kế bố cục
tương ứng, bạn có thể sử dụng BoxWithConstraints
. Bạn có thể tìm thấy các giới hạn về đo lường
trong phạm vi của nội dung lambda. Bạn có thể sử dụng các giới hạn đo lường này
để phát triển các bố cục khác nhau cho các cấu hình màn hình khác nhau:
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
Bố cục theo khe
Compose cung cấp nhiều loại thành phần kết hợp dựa trên Material
Design cùng với phần phụ thuộc
androidx.compose.material:material
(được bao gồm khi tạo một
dự án Compose trong Android Studio) để giúp bạn dễ dàng xây dựng Giao diện người dùng. Các thành phần như
Drawer
,
FloatingActionButton
và TopAppBar
đều được cung cấp.
Các thành phần cụ thể sử dụng nhiều API khe, một mẫu mà Compose đưa ra
để sử dụng một lớp tuỳ chỉnh ở phía cùng các thành phần kết hợp. Phương pháp tiếp cận này giúp
các thành phần linh hoạt hơn, vì chúng chấp nhận một thành phần con cháu có thể tự định cấu hình
thay vì phải biểu thị mọi thông số cấu hình của thành phần con cháu.
Các khe sẽ để trống trong giao diện người dùng để nhà phát triển lấp đầy theo ý muốn. Ví dụ: đây là các khe mà bạn có thể tuỳ chỉnh trong TopAppBar
:
Các thành phần kết hợp thường lấy một hàm lambda kết hợp content
(content: @Composable
() -> Unit
). API khe biểu thị nhiều thông số content
cho các mục đích sử dụng cụ thể.
Ví dụ: TopAppBar
cho phép bạn cung cấp nội dung cho title
,
navigationIcon
và actions
.
Ví dụ:
Scaffold
cho phép bạn triển khai giao diện người dùng với cấu trúc bố cục Material Design cơ bản.
Scaffold
cung cấp khe cho các thành phần Vật liệu cấp cao nhất phổ biến nhất,
chẳng hạn như TopAppBar
,
BottomAppBar
,
FloatingActionButton
và Drawer
. Bằng cách sử dụng
Scaffold
, việc đảm bảo các thành phần này được đặt đúng vị trí và
hoạt động cùng nhau một cách chính xác trở nên vô cùng đơn giản.
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Đối tượng sửa đổi Compose
- Kotlin cho Jetpack Compose
- Thành phần và bố cục Material