Giúp ứng dụng nhận biết chế độ gập

Màn hình lớn, gập lại được và các trạng thái gập độc đáo mang đến trải nghiệm người dùng mới mẻ trên các thiết bị có thể gập lại. Để giúp ứng dụng của bạn nhận biết được màn hình gập trong Jetpack Compose, hãy sử dụng thư viện Thích ứng Material 3 của Compose. Thư viện này cung cấp các API cho các tính năng cửa sổ của thiết bị có thể gập lại, chẳng hạn như màn hình đầu tiên, bản lề và tư thế thiết bị. Khi nhận biết được ứng dụng của bạn trong màn hình đầu tiên, ứng dụng có thể điều chỉnh bố cục để tránh đặt nội dung quan trọng trong màn hình đầu tiên hoặc bản lề, đồng thời sử dụng đường gấp và bản lề làm dấu phân tách tự nhiên.

Việc hiểu rõ liệu một thiết bị có hỗ trợ các cấu hình như tư thế trên mặt bàn hoặc tư thế quyển sách hay không có thể giúp bạn đưa ra quyết định về việc hỗ trợ các bố cục khác nhau hoặc cung cấp các tính năng cụ thể.

Thông tin về cửa sổ

Trong Jetpack Compose, hãy dùng hàm có khả năng kết hợp collectFoldingFeaturesAsState() để theo dõi thông tin về trạng thái gập của cửa sổ. collectFoldingFeaturesAsState() thu thập các tính năng gập cửa sổ hiện tại từ WindowInfoTracker vào một State Compose chứa danh sách các đối tượng FoldingFeature.

collectFoldingFeaturesAsState() trả về một State Compose, nên các thành phần kết hợp của bạn sẽ tự động kết hợp lại bất cứ khi nào trạng thái hoặc tư thế gập của thiết bị thay đổi mà không cần quản lý vòng đời hoặc thu thập luồng theo cách thủ công:

@Composable
fun FoldAwareScreen() {
    val foldingFeatures by collectFoldingFeaturesAsState()

    // Access folding features for the current window.
    val foldFeature = foldingFeatures.firstOrNull()
    if (foldFeature != null) {
        // Adapt layout based on the fold feature.
    }
}

Tính năng của màn hình có thể gập

Danh sách các phần tử FoldingFeature do collectFoldingFeaturesAsState() trả về (một loại con của DisplayFeature) cung cấp thông tin về màn hình có thể gập lại, bao gồm các thuộc tính sau:

  • state: Trạng thái gập của thiết bị, FLAT hoặc HALF_OPENED

  • orientation: Hướng của màn hình gập hoặc bản lề, HORIZONTAL hoặc VERTICAL

  • occlusionType: Liệu màn hình gập hay bản lề có che khuất một phần màn hình hay không, NONE hay FULL

  • isSeparating: Đường ranh giới phần hiển thị hoặc bản lề tạo ra hai khu vực hiển thị hợp lý, true hay false

Một thiết bị có thể gập lại được HALF_OPENED luôn báo cáo isSeparating là true vì màn hình được tách thành hai khu vực hiển thị. Ngoài ra, isSeparating luôn đúng trên thiết bị màn hình kép khi ứng dụng kéo dài trên cả hai màn hình.

Thuộc tính FoldingFeature bounds (kế thừa từ DisplayFeature) đại diện cho hình chữ nhật ranh giới của một tính năng gập lại, chẳng hạn như đường gập hoặc bản lề. Bạn có thể dùng các giới hạn để định vị các phần tử trên màn hình tương ứng với tính năng này:

@Composable
fun FoldFeatureDemo() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    if (foldFeature != null) {
        val isSeparating = foldFeature.isSeparating
        val occlusionType = foldFeature.occlusionType
        val bounds = foldFeature.bounds
        // Use bounds and properties to position content.
    }
}

Tư thế đặt trên mặt bàn

Khi sử dụng thông tin có trong đối tượng FoldingFeature, ứng dụng của bạn có thể hỗ trợ các tư thế như chế độ mặt bàn, khi điện thoại nằm trên một bề mặt, bản lề ở vị trí nằm ngang và màn hình có thể gập lại đang mở một nửa.

Chế độ trên mặt bàn giúp người dùng thao tác thuận tiện với điện thoại mà không cần cầm điện thoại trên tay. Tư thế đặt trên mặt bàn rất phù hợp để xem nội dung nghe nhìn, chụp ảnh và gọi video.

Một ứng dụng trình phát video ở tư thế mặt bàn, với chế độ phát video ở phần dọc thẳng đứng của màn hình và các nút điều khiển phát ở phần ngang phía dưới.
Hình 1. Một ứng dụng trình phát video ở tư thế mặt bàn – video trên phần dọc của màn hình; các nút điều khiển phát trên phần ngang.

Sử dụng FoldingFeature.StateFoldingFeature.Orientation từ collectFoldingFeaturesAsState() để xác định xem thiết bị có đang ở tư thế trên mặt bàn hay không:

@Composable
fun TabletopContent() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    val isTableTopPosture = foldFeature != null &&
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
        foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL

    if (isTableTopPosture) {
        // Tabletop layout: separate content and controls across the fold.
    } else {
        // Standard layout.
    }
}

Ngoài ra, bạn có thể xác định xem cửa sổ có ở tư thế trên mặt bàn hay không bằng cách kiểm tra thuộc tính Posture do currentWindowAdaptiveInfoV2() trả về:

val adaptiveInfo = currentWindowAdaptiveInfoV2()
val isTabletop = adaptiveInfo.windowPosture.isTabletop

Sau khi bạn biết thiết bị đang ở tư thế trên mặt bàn, hãy cập nhật bố cục ứng dụng cho phù hợp. Đối với các ứng dụng đa phương tiện, điều đó thường có nghĩa là đặt chế độ phát trong màn hình đầu tiên và đặt các nút điều khiển cũng như nội dung bổ sung ngay bên dưới để mang đến trải nghiệm xem hoặc nghe ở chế độ rảnh tay.

Ví dụ

Tư thế sách

Chế độ sách là một tính năng độc đáo khác của thiết bị có thể gập lại, trong đó thiết bị được mở một nửa và bản lề thẳng đứng. Tư thế sách rất phù hợp để đọc sách điện tử. Với bố cục 2 trang trên một màn hình lớn có thể gập lại và mở ra như một cuốn sách đóng bìa, tư thế sách sẽ mang lại trải nghiệm đọc như khi bạn đọc một cuốn sách thực.

Bạn cũng có thể dùng chế độ này để chụp ảnh nếu muốn chụp ảnh ở một tỷ lệ khung hình khác mà không cần dùng tay.

Triển khai tư thế sách bằng các kỹ thuật dùng để triển khai tư thế mặt bàn. Kiểm tra để đảm bảo rằng hướng của tính năng gập là hướng dọc thay vì hướng ngang:

@Composable
fun BookContent() {
    val foldingFeatures by collectFoldingFeaturesAsState()
    val foldFeature = foldingFeatures.firstOrNull()

    val isBookPosture = foldFeature != null &&
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
        foldFeature.orientation == FoldingFeature.Orientation.VERTICAL

    if (isBookPosture) {
        // Book posture layout: two-page layout across the vertical fold.
    } else {
        // Standard single-page layout.
    }
}

Thay đổi kích thước cửa sổ

Khu vực hiển thị của ứng dụng có thể thay đổi do thay đổi cấu hình thiết bị, ví dụ: khi thiết bị được gập lại hoặc gập lại, xoay hoặc đổi kích thước ở chế độ nhiều cửa sổ.

Để truy xuất lớp kích thước cửa sổ hiện tại và thích ứng với các thay đổi về kích thước trong Jetpack Compose, hãy sử dụng hàm composable currentWindowAdaptiveInfoV2() trong thư viện Thích ứng Compose Material 3. currentWindowAdaptiveInfoV2() trả về một thực thể WindowAdaptiveInfo cung cấp WindowSizeClass của cửa sổ hiện tại (theo mặc định, có hỗ trợ các điểm ngắt lớn và cực lớn), cũng như windowPosture của thiết bị:

@Composable
fun AdaptiveApp() {
    val adaptiveInfo = currentWindowAdaptiveInfoV2()
    val windowSizeClass = adaptiveInfo.windowSizeClass

    when {
        windowSizeClass.isWidthAtLeastBreakpoint(
            WIDTH_DP_EXPANDED_LOWER_BOUND
        ) -> {
            // Expanded layout
        }
        windowSizeClass.isWidthAtLeastBreakpoint(
            WIDTH_DP_MEDIUM_LOWER_BOUND
        ) -> {
            // Medium layout
        }
        else -> {
            // Compact layout
        }
    }
}

Xem phần Sử dụng các lớp kích thước cửa sổ.

Tài nguyên khác

Để tìm hiểu thêm về bố cục nhận biết chế độ gập và thiết bị có thể gập lại, hãy xem các tài nguyên sau:

Mẫu

Lớp học lập trình