一、概念
设备信息是动态更新的,需要对其进行监控,并在发生任何更新时触发重组。mediaQuery() 和 derivedMediaQuery() 函数抽象了信息检索的细节,让你可以专注于定义触发布局更新的条件。UiMediaScope 代表了当前的设备能力和上下文环境,当发生变化时此对象会动态更新,查询函数会使用更新后的 UiMediaScope 对象对 Lambda 进行求值。
|---------------------|---------------------------------------------------------------------------------------------------------------|
| mediaQuery() | @Composable fun mediaQuery( query: UiMediaScope.() -> Boolean ): Boolean = LocalUiMediaScope.current.query() |
| derivedMediaQuery() | @Composable fun derivedMediaQuery( query: UiMediaScope.() -> Boolean ): State<Boolean> |
|----------------------------------|---------------------------------------------------|---------------------------------------|
| UiMediaScope 参数 | 类型及说明 ||
| windowWidth windowHeight 当前窗口的宽高 | Dp ||
| windowPosture 当前设备姿态 | UiMediaScope.Posture | .Flat |
| windowPosture 当前设备姿态 | UiMediaScope.Posture | .Tabletop |
| windowPosture 当前设备姿态 | UiMediaScope.Posture | .Book |
| pointerPrecision 当前指针输入的最高精度 | UiMediaScope.PointerPrecision 同时存在多个输入设备会返回精度最高的。 | .Fine 精细:鼠标、触控板、手写笔。 |
| pointerPrecision 当前指针输入的最高精度 | UiMediaScope.PointerPrecision 同时存在多个输入设备会返回精度最高的。 | .Coarse 粗略:触摸屏(手指)。 |
| pointerPrecision 当前指针输入的最高精度 | UiMediaScope.PointerPrecision 同时存在多个输入设备会返回精度最高的。 | .Blunt 迟钝:摇杆。 |
| pointerPrecision 当前指针输入的最高精度 | UiMediaScope.PointerPrecision 同时存在多个输入设备会返回精度最高的。 | .None 无:没有输入方式。 |
| keyboardKind 可用的键盘类型 | UiMediaScope.KeyboardKind | .Physical 物理硬件。 |
| keyboardKind 可用的键盘类型 | UiMediaScope.KeyboardKind | .Virtual 虚拟键盘。 |
| keyboardKind 可用的键盘类型 | UiMediaScope.KeyboardKind | .None 无:未连接硬件也没有显示虚拟键盘。 |
| hasCamera 是否支持摄像头 | Boolean ||
| hasMicrophone 是否支持麦克风 | Boolean ||
| viewingDistance 用户与屏幕之间的典型距离 | UiMediaScope.ViewingDistance | .Near 近距离:大多数个人设备的默认设置,手机、平板、笔记本、显示器。 |
| viewingDistance 用户与屏幕之间的典型距离 | UiMediaScope.ViewingDistance | .Medium 稍远:车载设备、底座模式的平板。 |
| viewingDistance 用户与屏幕之间的典型距离 | UiMediaScope.ViewingDistance | .Far 相当远:电视。 |
二、使用
2.1 窗口大小
Kotlin
when {
mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}
2.2 设备形态
Kotlin
val isExpanded by derivedMediaQuery {
windowWidth >= WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp
}
val isMedium by derivedMediaQuery {
windowWidth >= WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp
}
when {
isExpanded -> ThreePaneLayout()
isMedium -> TwoPaneLayout()
else -> SinglePaneLayout()
}
2.3 输入精度
Kotlin
val buttonSize = if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Fine }) {
10.dp
} else {
20.dp
}
2.4 检测键盘
Kotlin
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) {
// 提示连接键盘
}
2.5 检测麦克风/摄像头
Kotlin
if (mediaQuery { hasMicrophone }) {
MicButton()
}
if (mediaQuery { hasCamera }) {
CameraButton()
}
2.5 检测距离
Kotlin
val fontSize = when {
mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp
mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp
else -> 16.sp
}
三、预览
Kotlin
@Composable
fun TablettopPreview() {
// 1.启用 mediaQuery 函数。
ComposeUiFlags.isMediaQueryIntegrationEnabled = true
val currentUiMediaScope = LocalUiMediaScope.current
// 2.定义一个实现 UiMediaScope 接口的自定义对象。
// 该对象覆盖了 windowPosture 参数,其余参数的解析将委托给 currentUiMediaScope 对象。
val uiMediaScope = remember(currentUiMediaScope) {
object : UiMediaScope by currentUiMediaScope {
override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop
}
}
// 3. 将该对象设置为 LocalUiMediaScope。
CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) {
// 4.调用组件进行预览
when {
mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}
}
}