Bạn cần nhiều loại thông tin, chẳng hạn như khả năng của thiết bị và trạng thái ứng dụng, để cập nhật bố cục ứng dụng. Chiều rộng và chiều cao cửa sổ là những thông tin thường được dùng nhất. Ngoài ra, bạn có thể tham khảo thông tin sau:
- Tư thế cửa sổ
- Độ chính xác của thiết bị trỏ
- Loại bàn phím
- Thiết bị có hỗ trợ camera và micrô hay không
- Khoảng cách giữa người dùng và màn hình thiết bị
Vì thông tin được cập nhật linh hoạt, nên bạn cần theo dõi thông tin đó và kích hoạt quá trình kết hợp lại khi có bất kỳ nội dung cập nhật nào.
Hàm mediaQuery trừu tượng hóa thông tin chi tiết về việc truy xuất thông tin và cho phép bạn tập trung vào việc xác định điều kiện kích hoạt các bản cập nhật bố cục.
Ví dụ sau đây sẽ chuyển bố cục sang TabletopLayout khi tư thế của thiết bị có thể gập lại là tư thế đặt trên bàn:
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Bật hàm mediaQuery
Để bật hàm mediaQuery, hãy đặt thuộc tính isMediaQueryIntegrationEnabled của đối tượng ComposeUiFlags thành true:
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
Xác định một điều kiện có tham số
Bạn có thể xác định một điều kiện dưới dạng lambda được đánh giá trong UiMediaScope.
Hàm mediaQuery đánh giá điều kiện theo trạng thái hiện tại và các chức năng của thiết bị.
Hàm này trả về một giá trị boolean, vì vậy bạn có thể xác định bố cục bằng các nhánh có điều kiện như biểu thức if.
Bảng 1 mô tả các tham số có trong UiMediaScope.
| Tham số | Loại giá trị | Mô tả |
|---|---|---|
windowWidth |
Dp |
Chiều rộng cửa sổ hiện tại tính bằng dp. |
windowHeight |
Dp |
Chiều cao hiện tại của cửa sổ, tính bằng dp. |
windowPosture |
UiMediaScope.Posture |
Tư thế hiện tại của cửa sổ ứng dụng. |
pointerPrecision |
UiMediaScope.PointerPrecision |
Độ chính xác cao nhất của các thiết bị trỏ hiện có. |
keyboardKind |
UiMediaScope.KeyboardKind |
Loại bàn phím có sẵn hoặc đã kết nối. |
hasCamera |
Boolean |
Xem thiết bị có hỗ trợ camera hay không. |
hasMicrophone |
Boolean |
Xem thiết bị có hỗ trợ micrô hay không. |
viewingDistance |
UiMediaScope.ViewingDistance |
Khoảng cách thông thường giữa người dùng và màn hình thiết bị. |
Một đối tượng UiMediaScope sẽ phân giải các giá trị của tham số.
Hàm mediaQuery dùng LocalUiMediaScope.current để truy cập vào đối tượng UiMediaScope, đối tượng này đại diện cho các chức năng và ngữ cảnh hiện tại của thiết bị.
Đối tượng này được cập nhật linh hoạt khi có bất kỳ thay đổi nào, chẳng hạn như khi người dùng thay đổi tư thế thiết bị.
Sau đó, hàm mediaQuery sẽ đánh giá lambda query bằng đối tượng UiMediaScope đã cập nhật và trả về một giá trị boolean.
Ví dụ: đoạn mã sau đây chọn giữa TabletopLayout và FlatLayout dựa trên giá trị tham số windowPosture.
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Đưa ra quyết định dựa trên kích thước cửa sổ
Lớp kích thước cửa sổ là một tập hợp các điểm ngắt khung hiển thị có ý kiến giúp bạn thiết kế, phát triển và kiểm thử các bố cục thích ứng.
Bạn có thể so sánh 2 thông số đại diện cho kích thước cửa sổ hiện tại với ngưỡng được xác định trong các lớp kích thước cửa sổ.
Ví dụ sau đây sẽ thay đổi số lượng ngăn theo chiều rộng cửa sổ.
Lớp WindowSizeClass có các hằng số cho ngưỡng của các lớp kích thước cửa sổ (Hình 1).
Hàm derivedMediaQuery đánh giá lambda query và gói kết quả trong derivedStateOf.
Vì windowWidth và windowHeight có thể cập nhật thường xuyên, hãy gọi hàm derivedMediaQuery thay vì hàm mediaQuery khi bạn tham chiếu đến các tham số đó trong lambda query.
val narrowerThanMedium by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp } val narrowerThanExpanded by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp } when { narrowerThanMedium -> SinglePaneLayout() narrowerThanExpanded -> TwoPaneLayout() else -> ThreePaneLayout() }
Cập nhật bố cục theo tư thế cửa sổ
Tham số windowPosture mô tả tư thế hiện tại của cửa sổ dưới dạng một đối tượng UiMediaScope.Posture.
Bạn có thể kiểm tra posture hiện tại bằng cách so sánh tham số với các giá trị được xác định trong lớp UiMediaScope.Posture.
Ví dụ sau đây chuyển đổi bố cục theo tư thế cửa sổ:
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
Kiểm tra độ chính xác của thiết bị trỏ hiện có
Thiết bị trỏ có độ chính xác cao giúp người dùng trỏ chính xác một phần tử trên giao diện người dùng. Độ chính xác của thiết bị trỏ phụ thuộc vào loại thiết bị.
Tham số pointerPrecision mô tả độ chính xác của các thiết bị trỏ hiện có, chẳng hạn như chuột và màn hình cảm ứng.
Có 4 giá trị được xác định trong lớp UiMediaScope.PointerPrecision: Fine, Coarse, Blunt và None.
None có nghĩa là không có thiết bị trỏ nào.
Độ chính xác từ cao nhất đến thấp nhất theo thứ tự sau: Fine, Coarse và Blunt.
Nếu có nhiều thiết bị trỏ và độ chính xác của chúng khác nhau, thì tham số sẽ được phân giải bằng tham số có độ chính xác cao nhất.
Ví dụ: nếu có 2 thiết bị trỏ – một thiết bị có độ chính xác Fine và một thiết bị có độ chính xác Blunt – thì Fine là giá trị của tham số pointerPrecision.
Ví dụ sau đây cho thấy một nút lớn hơn khi người dùng đang sử dụng thiết bị trỏ có độ chính xác thấp:
if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) { LargeSizeButton() } else { NormalSizeButton() }
Kiểm tra loại bàn phím hiện có
Tham số keyboardKind biểu thị loại bàn phím hiện có: Physical, Virtual và None.
Nếu bàn phím ảo xuất hiện và bàn phím phần cứng cũng có sẵn cùng lúc, thì tham số sẽ được phân giải thành Physical.
Nếu không phát hiện được giá trị nào, thì None là giá trị của tham số.
Ví dụ sau đây cho thấy một thông báo đề xuất người dùng kết nối bàn phím khi không phát hiện thấy bàn phím:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Kiểm tra xem thiết bị có hỗ trợ camera và micrô hay không
Một số thiết bị không hỗ trợ camera hoặc micrô.
Bạn có thể kiểm tra xem thiết bị có hỗ trợ camera và micrô hay không bằng tham số hasCamera và tham số hasMicrophone.
Ví dụ sau đây minh hoạ các nút để sử dụng với camera và micrô khi thiết bị hỗ trợ các nút này:
Row { OutlinedTextField(state = rememberTextFieldState()) // Show the MicButton when the device supports a microphone. if (mediaQuery { hasMicrophone }) { MicButton() } // Show the CameraButton when the device supports a camera. if (mediaQuery { hasCamera }) { CameraButton() } }
Điều chỉnh giao diện người dùng theo khoảng cách xem ước tính
Khoảng cách xem là một yếu tố giúp xác định bố cục.
Nếu đang sử dụng ứng dụng từ xa, người dùng sẽ muốn văn bản và các phần tử trên giao diện người dùng có kích thước lớn hơn.
Tham số viewingDistance cung cấp thông tin ước tính về khoảng cách xem dựa trên loại thiết bị và bối cảnh sử dụng thông thường của thiết bị đó.
Có 3 giá trị được xác định trong lớp UiMediaScope.ViewingDistance: Near, Medium và Far.
Near có nghĩa là màn hình ở phạm vi gần và Far có nghĩa là thiết bị được xem từ xa.
Ví dụ sau đây sẽ tăng cỡ chữ khi khoảng cách xem là Far hoặc Medium:
val fontSize = when { mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp else -> 16.sp }
Xem trước một thành phần giao diện người dùng
Bạn có thể gọi các hàm mediaQuery và derivedMediaQuery trong các hàm có khả năng kết hợp để xem trước các thành phần giao diện người dùng.
Đoạn mã sau đây chọn giữa TabletopLayout và FlatLayout dựa trên giá trị tham số windowPosture.
Để xem trước TabletopLayout, tham số windowPosture phải là UiMediaScope.Posture.Tabletop.
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
Hàm mediaQuery và derivedMediaQuery đánh giá hàm lambda query đã cho trong một đối tượng UiMediaScope, được cung cấp dưới dạng LocalUiMediaScope.current.
Bạn có thể ghi đè bằng cách làm theo các bước sau:
- Bật hàm
mediaQuery. - Xác định một đối tượng tuỳ chỉnh triển khai giao diện
UiMediaScope. - Đặt đối tượng tuỳ chỉnh thành
LocalUiMediaScopebằng hàmCompositionLocalProvider. - Gọi thành phần kết hợp để xem trước trong biểu thức lambda nội dung của hàm
CompositionLocalProvider.
Bạn có thể xem trước TabletopLayout bằng ví dụ sau:
@Preview @Composable fun PreviewLayoutForTabletop() { // Step 1: Enable the mediaQuery function ComposeUiFlags.isMediaQueryIntegrationEnabled = true val currentUiMediaScope = LocalUiMediaScope.current // Step 2: Define a custom object implementing the UiMediaScope interface. // The object overrides the windowPosture parameter. // The resolution of the remaining parameters is deferred to the currentUiMediaScope object. val uiMediaScope = remember(currentUiMediaScope) { object : UiMediaScope by currentUiMediaScope { override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop } } // Step 3: Set the object to the LocalUiMediaScope. CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) { // Step 4: Call the composable to preview. when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() } } }