一、概念
屏幕适配除了尺寸,现在还有形态。
二、基本使用
2.1 获取 FoldingFeature
WindowInfoTracker 会公开窗口布局信息,通过 WindowInfoTracker.getOrCreater() 创建,它的 windowLayoutInfo() 方法会返回一个 WindowLayoutInfo 类型的数据流,将可折叠设备的折叠状态告知你的应用。对于该数据流的处理,调用 collectAsState() 转为 Compose 状态使用,如果是直接收集流的场景,生命周期选择 STARTED。WindowManager 会以 DisplayFeature 类型的 List 形式提供显示窗口的功能,通过过滤获取其中有关折叠屏信息的 FoldingFeature。
val foldingFeature = WindowInfoTracker
.getOrCreate(context) //获取实例
.windowLayoutInfo(context) //返回数据流
.collectAsState(null) //转为Compose状态使用
.value //获取可观察容器中的值
?.displayFeatures //获取提供显示窗口功能的列表
?.filterIsInstance<FoldingFeature>() //获取其中有关折叠屏的信息
?.firstOrNull()
2.2 判断折叠信息
通过 FoldingFeature 的字段获取折叠信息,state 折叠状态,orientation 折叠方向,isSeparating 屏幕是否被分为两个显示区域,occlusionType 折叠处是否遮挡显示。
FoldingFeature |
.State 折叠状态。 |
.FLAT 展开 |
.HALF_OPENED 半折叠 | ||
.Orientation 折叠处(铰链/折痕)方向。 |
.HORIZONTAL 横向(半折叠状态下,横向就是桌面模式)。 | |
.VERTICAL 纵向(半折叠状态下,纵向就是图书模式)。 | ||
isSeparating() 屏幕是否被分为两个显示区域。 |
true (半折叠或跨越双屏情况下,始终返回true)。 | |
false | ||
.occlusionType 折叠处是否遮挡显示。 |
NONE 折叠处能显示内容,一般无需处理,除非影响阅读交互。 | |
FULL 折叠处会遮挡内容,像双屏连接处就是,需要通过 bounds 来留白或偏移界面元素。 | ||
.bounds 折叠处矩形区域。 | 是一个 Rect 类型,该区域一般不方便交互,用于留白或偏移界面元素。 |
2.3 分类加载逻辑
对于 WindowSizeClasses 的 Medium 或 Expanded 需要进行折叠状态的判断,如果是展开状态直接沿用布局,如果是半折叠状态需要通过折叠边方向分别为桌面模式和图书模式进行布局设计。
@Composable
fun Demo(
windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
//根据判断结果,分别加载不同界面或对变量赋值,顺序必须从大到小
if (windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND)) {
if (AppTheme.isTableTopPosture()) {
DeskScreen()
} else if (AppTheme.isBookPosture()) {
BookScreen()
} else {
ExpandedScreen()
}
} else if (windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND)) {
//同上
} else {
CompactScreen()
}
}
三、封装进自定义主题
//通过全局入口AppTheme获取更符合直觉,因此设为private
private val LocalFoldingFeature = compositionLocalOf<FoldingFeature?> { null }
object AppTheme {
//用于获取折叠屏信息
val foldFeature: FoldingFeature?
@Composable get() = LocalFoldingFeature.current
/**
* 判断折叠屏是不是桌面模式
*/
@Composable
fun isTableTopPosture() : Boolean {
val foldFeature = LocalFoldingFeature.current
return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
}
/**
* 判断折叠屏是不是图书模式
*/
@Composable
fun isBookPosture() : Boolean {
val foldFeature = LocalFoldingFeature.current
return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
}
}
@Composable
fun AppTheme(
content: @Composable () -> Unit
) {
val context = LocalContext.current
val foldingFeature = WindowInfoTracker
.getOrCreate(context)
.windowLayoutInfo(context)
.collectAsState(null)
.value
?.displayFeatures
?.filterIsInstance<FoldingFeature>()
?.firstOrNull()
CompositionLocalProvider(
LocalFoldingFeature provides foldingFeature
){
content()
}
}