Đối với ứng dụng truyền hình, trải nghiệm duyệt xem dựa vào tính năng điều hướng dựa trên tiêu điểm hiệu quả. Khi sử dụng bố cục tải từng phần của Compose Foundation tiêu chuẩn, bạn có thể tạo danh sách dọc và ngang hiệu quả, tự động xử lý thao tác cuộn dựa trên tiêu điểm để giữ cho các mục đang hoạt động luôn hiển thị.
Hành vi cuộn mặc định được tối ưu hoá cho TV
Kể từ Compose Foundation 1.7.0, bố cục tải từng phần chuẩn (như LazyRow và LazyColumn) có hỗ trợ tích hợp cho các tính năng định vị tiêu điểm. Đây là cách nên dùng để tạo danh mục cho ứng dụng truyền hình vì cách này giúp các mục được lấy tiêu điểm luôn hiển thị và được đặt ở vị trí trực quan cho người dùng.
Để triển khai một danh sách có thể cuộn cơ bản, hãy sử dụng các thành phần tải từng phần tiêu chuẩn. Các thành phần này tự động xử lý thao tác điều hướng bằng D-pad và đưa mục được lấy tiêu điểm vào khung hiển thị.
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items @Composable fun MovieCatalog(movies: List<Movie>) { LazyRow { items(movies) { movie -> MovieCard( movie = movie, onClick = { /* Handle click */ } ) } } }
Tuỳ chỉnh hành vi cuộn bằng BringIntoViewSpec
Nếu thiết kế của bạn yêu cầu một điểm "xoay" cụ thể (ví dụ: giữ cho mục được lấy tiêu điểm cách cạnh trái chính xác 30%), bạn có thể tuỳ chỉnh hành vi cuộn bằng BringIntoViewSpec. Thao tác này thay thế chức năng pivotOffsets cũ bằng cách cho phép bạn xác định chính xác cách khung nhìn sẽ cuộn để phù hợp với một mục được lấy tiêu điểm.
1. Xác định BringIntoViewSpec tuỳ chỉnh
Thành phần kết hợp trợ giúp sau đây cho phép bạn xác định "trục" dựa trên các phân số của thành phần mẹ và thành phần con. parentFraction xác định vị trí mà mục sẽ xuất hiện trong vùng chứa và childFraction xác định phần nào của mục sẽ căn chỉnh với điểm đó.
@OptIn(ExperimentalFoundationApi::class) @Composable fun PositionFocusedItemInLazyLayout( parentFraction: Float = 0.3f, childFraction: Float = 0f, content: @Composable () -> Unit, ) { val bringIntoViewSpec = remember(parentFraction, childFraction) { object : BringIntoViewSpec { override fun calculateScrollDistance( offset: Float, // Item's initial position size: Float, // Item's size containerSize: Float // Container's size ): Float { // Calculate the offset position of the item's leading edge. val initialTargetForLeadingEdge = parentFraction * containerSize - (childFraction * size) // If the item fits in the container, and scrolling would cause // its trailing edge to be clipped, adjust targetForLeadingEdge // to prevent over-scrolling near the end of list. val targetForLeadingEdge = if (size <= containerSize && (containerSize - initialTargetForLeadingEdge) < size) { // If clipped, align the item's trailing edge with the // container's trailing edge. containerSize - size } else { initialTargetForLeadingEdge } // Return scroll distance relative to initial item position. return offset - targetForLeadingEdge } } } // Apply the spec to all scrollables in the hierarchy CompositionLocalProvider( LocalBringIntoViewSpec provides bringIntoViewSpec, content = content, ) }
2. Áp dụng thông số kỹ thuật tuỳ chỉnh
Gói bố cục của bạn bằng trình trợ giúp để áp dụng vị trí. Điều này rất hữu ích cho việc tạo "đường tiêu điểm nhất quán" trên các hàng khác nhau trong danh mục của bạn.
PositionFocusedItemInLazyLayout( parentFraction = 0.3f, // Pivot 30% from the edge childFraction = 0.5f // Center of the item aligns with the pivot ) { LazyColumn { items(sectionList) { section -> // This row and its items will respect the 30% pivot LazyRow { /* ... */ } } } }
3. Chọn không tham gia cho các bố cục lồng nhau cụ thể
Nếu bạn có một bố cục lồng nhau cụ thể nên sử dụng hành vi cuộn chuẩn thay vì trục tuỳ chỉnh, hãy cung cấp DefaultBringIntoViewSpec:
private val DefaultBringIntoViewSpec = object : BringIntoViewSpec {} PositionFocusedItemInLazyLayout { LazyColumn { item { // This row will ignore the custom pivot and use default behavior CompositionLocalProvider(LocalBringIntoViewSpec provides DefaultBringIntoViewSpec) { LazyRow { /* ... */ } } } } }
Trên thực tế, việc truyền một BringIntoViewSpec trống sẽ cho phép hành vi mặc định của khung tiếp quản.
Di chuyển từ TV Foundation sang Compose Foundation
Bố cục tải từng phần dành riêng cho TV trong androidx.tv.foundation không còn được dùng nữa mà thay vào đó là bố cục Compose Foundation tiêu chuẩn.
Thông tin cập nhật về phần phụ thuộc
Xác minh rằng build.gradle của bạn sử dụng phiên bản 1.7.0 trở lên cho:
androidx.compose.foundationandroidx.compose.runtime
Liên kết thành phần
Để di chuyển, hãy cập nhật các lệnh nhập và xoá tiền tố Tv khỏi các thành phần:
| Thành phần TV không dùng nữa | Thay thế Compose Foundation |
|---|---|
| TvLazyRow | LazyRow |
| TvLazyColumn | LazyColumn |
| TvLazyHorizontalGrid | LazyHorizontalGrid |
| TvLazyVerticalGrid | LazyVerticalGrid |
| pivotOffsets | BringIntoViewSpec (thông qua LocalBringIntoViewSpec) |