Compose 适配 - 分辨率(密度)

View体系适配跳转

参考文章

一、概念

目前 Compose 只能采用 dp 单位设置尺寸, Dp.roundToPx() 方法与 View 体系中 applyDimension() 方法一样最终都是通过 px = dp * density 公式将 dp 转为 px。

连接 Compose 和 View 体系之间的桥梁是 AndroidComposeView 类,而 AndroidComposeView 就通过 fun Density(context: Context) 方法来初始化其内部声明的 density 对象,CompositionLocals 类的 ProvideCommonCompositionLocals 方法又通过 LocalDensity 来将 AndroidComposeView 持有的 density 对象暴露给外部,从而使得框架内部和开发者均可以通过 LocalDensity.current 来获取到当前的 Density 对象,也即通过此方法拿到了 Android 系统的 density 和 fontScale 两个参数。

得益于 CompositionLocalProvider 特性,能细腻度的控制修改后的密度生效范围(当前Activity甚至某个组合中)而不会影响全局,由次解决了View体系适配中字节跳动方案的缺点。

二、适配

2.1 dp

smallestWidth 方案也一样适用于Compose,通过 dimensionResource( ) 方法获取 res 中 dimen 值会转换为 Dp 类型,如果项目中已经使用了 smallestWidth 方案依然可以继续使用。

Kotlin 复制代码
/**
 * 根据UI设计图得出动态密度适配不同屏幕(以短边为准)
 * @param designWidth 填入UI设计图的屏幕短边dp值(绝对宽度)
 * @param designHeight 填入UI设计图的屏幕长边dp值(绝对高度)
 */
@Composable
private fun dynamicDensity(designWidth: Float, designHeight: Float): Float {
    val displayMetrics = LocalContext.current.resources.displayMetrics
    val widthPixels = displayMetrics.widthPixels    //屏幕短边像素(绝对宽度)
    val heightPixels = displayMetrics.heightPixels  //屏幕长边像素(绝对高度)
    val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT  //判断横竖屏
    return if (isPortrait) widthPixels / designWidth else heightPixels / designHeight //计算密度
}
Kotlin 复制代码
@Composable
fun AppTheme(
    content: @Composable () -> Unit
) {
    private val fontScale = LocalDensity.current.fontScale
    private val appDensity = Density(density = dynamicDensity(360F, 640F), fontScale = fontScale)
    CompositionLocalProvider(
        LocalDensity provides appDensity
    ){
        content()
    }
}

2.1.1 解决修改密度导致WindowSizeClass判断错误问题

UI图给的宽高一般都是根据手机设计的,修改密度后,作用域内获取 WindowSizeClass 进行屏幕大小判断的结果总是 COMPACT。因此定义一个 ComposeLocal,在自定义主题初始化时获取 WindowSizeClass,赋值给 CompositionLocalProvider 来提供全局获取。

2.2 sp

px = sp * fontScale * density,fontScale 代表当前系统字体的缩放比例,通过 LocalDensity.current.fontScale 获取该值,可以自由控制应用内文字的显示大小。

2.3 BoxWithConstraints

提供了一些现有参数,用来根据可用空间调用不同的布局方案。

|------|---------------------------------------------------------------------------------------|
| 单位dp | minWidth、minHeight、maxWidth、maxHeight |
| 单位px | constraints.minWidth constraints.minHeight constraints.maxWidth constraints.maxHeight |

Kotlin 复制代码
BoxWithConstraints {
    //根据可用宽度显示不同布局方案
    if(maxWidth < 400.dp) {
        Column{...}
    } else {
        Row{...}
    }
}
相关推荐
_祝你今天愉快12 小时前
从驱动来分析服务的添加过程
android
Dovis(誓平步青云)15 小时前
折叠屏悬停看视频,上半屏和下半屏应该各做什么
android·java·服务器·开发语言·安全·音视频
alexhilton16 小时前
让架构边界变成可执行的测试
android·kotlin·android jetpack
hai_android17 小时前
SendChannel 与 ReceiveChannel 通信机制
android
数据治理自习室19 小时前
AI 应用评测体系(GraphRAG)
android·大数据·人工智能·kotlin
爱笑鱼20 小时前
Android 系统启动机制(五):system_server 是 init 启动的,还是 Zygote fork 出来的?
android
智购科技无人售货机工厂21 小时前
2026自动售货机防拆机物理安全设计:从安全螺丝到结构互锁的工程实践~YH
android·网络·驱动开发·python·单片机·安全·云原生
开开心心就好21 小时前
电子教鞭工具支持画框写字插图片功能齐全
android·开发语言·前端·javascript·人工智能·pdf·html
Dovis(誓平步青云)21 小时前
拍视频前先把镜头想清楚:做一个分镜取景辅助器
android·java·服务器·javascript·人工智能
峥嵘life1 天前
Android16 系统 APEX 模块说明
android·大数据·开发语言