如何在Compose Multiplatform中不使用expect/actual获取屏幕尺寸?
在Compose Multiplatform中不使用expect/actual获取尺寸的方案实现
核心思路
通过Layout作为根Composable,利用其传入的constraints获取当前可用空间尺寸,再通过CompositionLocal将尺寸传递到整个Compose树中。该方案不依赖平台实现,能拿到当前Composable的实际可用尺寸(若根Layout铺满屏幕,则等价于屏幕可用区域尺寸)。
完整实现步骤
- 定义尺寸传递的CompositionLocal
首先创建一个CompositionLocal来承载尺寸数据,方便在Compose树中全局访问:
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember // 封装尺寸数据的数据类 data class WindowSize(val width: Int, val height: Int) // 创建CompositionLocal,默认值为(0,0) val LocalWindowSize = compositionLocalOf { WindowSize(0, 0) }
- 实现根Layout组件
编写一个自定义Layout作为App的根组件,在其中获取约束尺寸并更新CompositionLocal的值:
import androidx.compose.foundation.layout.Layout import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.MeasureScope import androidx.compose.ui.unit.Constraints @Composable fun WindowSizeLayout(content: @Composable () -> Unit) { // 保存当前尺寸,支持状态更新(比如屏幕旋转、窗口调整) var windowSize by remember { mutableStateOf(WindowSize(0, 0)) } Layout( content = { // 通过CompositionLocalProvider将最新尺寸传递给子组件 CompositionLocalProvider(LocalWindowSize provides windowSize) { content() } } ) { measurables, constraints -> // 获取当前Layout的最大可用尺寸 val newSize = WindowSize(constraints.maxWidth, constraints.maxHeight) // 尺寸变化时更新状态,触发重组 if (newSize != windowSize) { windowSize = newSize } // 测量子组件,让其铺满整个可用空间 val placeables = measurables.map { it.measure(constraints) } // 布局子组件,铺满整个Layout区域 layout(constraints.maxWidth, constraints.maxHeight) { placeables.forEach { it.place(0, 0) } } } }
- 在子组件中使用尺寸
在任意子Composable中,通过LocalWindowSize.current即可获取当前可用尺寸:
import androidx.compose.material.Text import androidx.compose.ui.unit.dp @Composable fun DisplayCurrentSize() { val size = LocalWindowSize.current Text( text = "可用宽度:${size.width.dp}\n可用高度:${size.height.dp}" ) }
- 在App根组件中应用
将WindowSizeLayout作为App的根容器,包裹所有内容:
@Composable fun MyApp() { WindowSizeLayout { // 这里放置你的整个App内容 DisplayCurrentSize() // 其他自定义Composable... } }
注意事项
- 该方案获取的是当前Layout的可用空间尺寸,若根Layout未铺满屏幕(比如存在系统状态栏、导航栏),则尺寸会扣除这些区域的空间。如果需要设备物理屏幕的原始尺寸,仍需使用
expect/actual方案。 - 当屏幕旋转、窗口大小调整时,尺寸会自动更新,无需额外监听逻辑。
内容的提问来源于stack exchange,提问作者Roy Solberg
相关产品推荐
相关产品推荐

