自适应布局
自适应布局 · androidx.window
Window:追踪折叠与窗口特征Window 1.6.0-alpha05
用 WindowInfoTracker 的 Flow 观察 WindowLayoutInfo 和 FoldingFeature。
最后更新 2026-08-01
复制即用
val tracker = WindowInfoTracker.getOrCreate(activity)
activity.lifecycleScope.launch {
activity.repeatOnLifecycle(Lifecycle.State.STARTED) {
tracker.windowLayoutInfo(activity).collect { layoutInfo ->
val fold = layoutInfo.displayFeatures
.filterIsInstance<FoldingFeature>()
.firstOrNull()
renderFor(fold)
}
}
}关键:windowLayoutInfo 是持续变化的 Flow,不是一次性设备检测。收集必须绑定可见生命周期(repeatOnLifecycle),避免页面不可见后仍持有 Activity。
FoldingFeature 属性
val fold = ... as FoldingFeature
fold.state // FLAT / HALF_OPENED
fold.orientation // HORIZONTAL / VERTICAL
fold.occlusionType // NONE / FULL(遮挡屏幕)
fold.isSeparating // 是否分隔成两个 pane
fold.bounds // 折痕区域判断原则:
- 有折痕不必然要分两个 pane——先看
isSeparating(是否分隔内容)。 occlusionType判断是否遮挡(铰链遮挡屏幕时内容要避开)。bounds决定实际分隔边界在哪。- 普通直板设备的
displayFeatures为空——正常结果,不是错误。
分隔布局示例
@Composable
fun FoldAwareLayout(fold: FoldingFeature?, content: @Composable () -> Unit) {
if (fold == null || !fold.isSeparating) {
// 单面板:正常内容
content()
return
}
// 折叠分隔:双面板布局
val bounds = fold.bounds
if (fold.orientation == FoldingFeature.Orientation.VERTICAL) {
Row(Modifier.fillMaxSize()) {
Box(Modifier.weight(1f).size(width = bounds.width.toDp())) { /* 左 */ }
Box(Modifier.weight(1f)) { /* 右 */ }
}
}
}常见陷阱
- 当成一次性查询:
windowLayoutInfo是 Flow,窗口变化(旋转/折叠展开)会重发。 - 不在 repeatOnLifecycle:后台仍收集,持有 Activity。
- 把有折痕=必须分栏:
isSeparating=false时折痕不分割内容。 - 忽略 occlusion:铰链遮挡屏幕时内容显示在遮挡区。
- Compose 忘 API:Compose 优先用
currentWindowAdaptiveInfoV2(),这个底层 API 给自定义场景。
复制即用
class MainActivity : ComponentActivity() {
private val tracker by lazy { WindowInfoTracker.getOrCreate(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
tracker.windowLayoutInfo(this@MainActivity).collect { info ->
val fold = info.displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull()
updateLayout(fold)
}
}
}
}
}要点
WindowInfoTracker.windowLayoutInfo是持续 Flow;绑定可见生命周期收集。FoldingFeature看isSeparating/occlusionType/bounds决定布局。- 直板设备 displayFeatures 为空是正常。
- Compose 场景优先
currentWindowAdaptiveInfoV2()。