Trong Compose, các thành phần trên giao diện người dùng được biểu thị bằng các hàm có khả năng kết hợp cung cấp một phần giao diện người dùng khi được gọi, sau đó được thêm vào cây giao diện người dùng hiển thị trên màn hình. Mỗi thành phần trên giao diện người dùng có một phần tử mẹ và có thể có nhiều phần tử con. Mỗi phần tử đều nằm trong phần tử mẹ, được xác định theo vị trí (x, y) và kích thước, được chỉ định là width
và height
.
Phần tử mẹ xác định các quy tắc ràng buộc cho các phần tử con. Một phần tử được yêu cầu xác định kích thước riêng trong các ràng buộc đó. Các ràng buộc hạn chế width
và height
tối thiểu và tối đa của một phần tử. Nếu một phần tử có các phần tử con thì phần tử đó có thể đo lường từng phần tử con để giúp xác định kích thước của phần tử đó. Sau khi một phần tử xác định và báo cáo kích thước riêng, phần tử này có cơ hội xác định cách đặt các phần tử con tương ứng với nó, như mô tả chi tiết trong phần Tạo bố cục tuỳ chỉnh.
Việc sắp xếp từng nút trong cây giao diện người dùng là quá trình 3 bước. Mỗi nút phải:
- Đo lường mọi phần tử con
- Quyết định kích thước riêng
- Đặt phần tử con của mình
Việc sử dụng phạm vi giúp xác định thời điểm bạn có thể đo lường và đặt thành phần con.
Bạn chỉ đo lường được bố cục trong quá trình chuyển bố cục và đo lường, đồng thời chỉ có thể đặt thành phần con trong quá trình chuyển bố cục (và chỉ sau khi thành phần con đó được đo lường). Do các phạm vi của Compose như MeasureScope
và PlacementScope
nên chúng tôi thực thi quá trình này trong thời gian biên dịch.
Sử dụng đối tượng sửa đổi bố cục
Bạn có thể sử dụng đối tượng sửa đổi layout
để sửa đổi cách đo lường và bố trí một phần tử. Layout
là lambda - thông số của giá trị này bao gồm phần tử mà bạn có thể đo lường được chuyển dưới dạng measurable
và các giới hạn sắp tới của những yếu tố có thể kết hợp, được chuyển dưới dạng constraints
. Công cụ sửa đổi bố cục tuỳ chỉnh có thể có dạng như sau:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Chúng ta hãy hiển thị một Text
trên màn hình và kiểm soát khoảng cách từ trên cùng đến đường cơ sở của dòng văn bản đầu tiên. Đây chính xác là những gì paddingFromBaseline
sửa đổi, chúng tôi sẽ triển khai ở đây làm ví dụ.
Để thực hiện điều này, hãy sử dụng công cụ sửa đổi layout
để tự đặt yếu tố có thể kết hợp trên màn hình. Dưới đây là hành vi mong muốn, trong đó khoảng đệm trên Text
được đặt 24.dp
:
Dưới đây là mã tạo khoảng trống đó:
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
Sau đây là những gì xảy ra trong mã đó:
- Trong tham số lambda
measurable
, bạn đo lườngText
(do tham số có thể đo lường đại diện) bằng cách gọimeasurable.measure(constraints)
. - Bạn chỉ định kích thước của thành phần kết hợp bằng cách gọi phương thức
layout(width, height)
. Phương thức này cũng cung cấp một lambda dùng để đặt các thành phần được gói. Trong trường hợp này, đó là chiều cao giữa đường cơ sở cuối cùng và khoảng đệm trên cùng được thêm vào. - Bạn định vị các thành phần được bao bọc trên màn hình bằng cách gọi
placeable.place(x, y)
. Nếu không được đặt thì các phần tử được bao bọc sẽ không hiển thị. Vị tríy
tương ứng với khoảng đệm trên cùng – vị trí của đường cơ sở đầu tiên của văn bản.
Để xác minh tính năng này hoạt động như dự kiến, hãy sử dụng công cụ sửa đổi này trên Text
:
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }
Tạo bố cục tuỳ chỉnh
Đối tượng sửa đổi layout
chỉ thay đổi các thành phần kết hợp thực hiện lệnh gọi. Để đo lường và bố trí nhiều thành phần kết hợp, hãy sử dụng thành phần kết hợp Layout
. Thành phần kết hợp này có thể giúp bạn đo lường và bố trí thành phần con theo cách thủ công. Tất cả các bố cục cấp cao hơn như Column
và Row
được tạo bằng thành phần kết hợp Layout
.
Hãy tạo một phiên bản Column
rất cơ bản. Hầu hết các bố cục tuỳ chỉnh đều theo mẫu sau:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
Tương tự như công cụ sửa đổi layout
, measurables
là danh sách các yếu tố con cần đo lường và constraints
là các hạn chế từ yếu tố gốc.
Theo nguyên lý tương tự như trước đây, bạn có thể triển khai MyBasicColumn
như sau:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
Các yếu tố có thể kết hợp con có thể bị hạn chế do các quy tắc ràng buộc của Layout
(không có quy tắc ràng buộc của minHeight
) và chúng được đặt dựa trên yPosition
của yếu tố có thể kết hợp trước đó.
Dưới đây là cách sử dụng yếu tố có thể kết hợp tuỳ chỉnh:
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }
Hướng bố cục
Thay đổi hướng bố cục của một yếu tố có thể kết hợp bằng cách thay đổi thành phần
LocalLayoutDirection
trên thiết bị.
Nếu bạn đặt thành phần kết hợp lên màn hình theo cách thủ công, thì LayoutDirection
sẽ thuộc LayoutScope
của đối tượng sửa đổi layout
hoặc thành phần kết hợp Layout
.
Khi sử dụng layoutDirection
, hãy đặt yếu tố có thể kết hợp bằng cách sử dụng place
. Không giống như phương thức
placeRelative
,
place
không thay đổi theo hướng bố cục
(từ trái sang phải so với từ phải sang trái).
Bố cục tuỳ chỉnh trong thực tế
Hãy tìm hiểu thêm về bố cục và đối tượng sửa đổi trong phần Bố cục cơ bản trong Compose, cũng như xem bố cục tuỳ chỉnh thực tế trong phần Mẫu Compose tạo bố cục tuỳ chỉnh.
Tìm hiểu thêm
Để tìm hiểu thêm về bố cục tuỳ chỉnh trong Compose, hãy tham khảo thêm những tài nguyên sau đây.
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
- Phép đo nội tại trong bố cục Compose
- Đồ hoạ trong Compose
- Đối tượng sửa đổi Compose