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.
Vì 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ị,FLAThoặcHALF_OPENEDorientation: Hướng của màn hình gập hoặc bản lề,HORIZONTALhoặcVERTICALocclusionType: 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,NONEhayFULLisSeparating: Đườ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.
Sử dụng FoldingFeature.State và FoldingFeature.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ụ
Ứng dụng
MediaPlayerActivity: Xem cách sử dụng Media3 Exoplayer và WindowManager để tạo một trình phát video có tính năng nhận biết chế độ gập.Lớp học lập trình Tối ưu hoá ứng dụng camera trên thiết bị gập nhờ Jetpack WindowManager: Tìm hiểu cách triển khai tư thế trên mặt bàn cho các ứng dụng chụp ảnh. Hiển thị kính ngắm ở nửa trên của màn hình (trong màn hình đầu tiên) và các chế độ điều khiển ở nửa dưới.
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
- Mẫu Jetpack WindowManager: Ví dụ về cách sử dụng thư viện Jetpack WindowManager
- Jetcaster : Triển khai tư thế trên mặt bàn bằng Compose
Lớp học lập trình
- Hỗ trợ thiết bị gập được và thiết bị màn hình đôi nhờ Jetpack WindowManager
- Tối ưu hoá ứng dụng máy ảnh trên thiết bị có thể gập lại nhờ Jetpack WindowManager