一、概念
- 目前 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 方案依然可以继续使用。
/**
* 根据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 = LocalContext.current.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT //判断横竖屏
return if (isPortrait) widthPixels / designWidth else heightPixels / designHeight //计算密度
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = {
CompositionLocalProvider(
LocalDensity provides Density(
density = dynamicDensity(360F, 640F), //假设是这两个值
fontScale = fontScale
)
) {
content()
}
}
)
2.2 sp
px = sp * fontScale * density,fontScale 代表当前系统字体的缩放比例,通过 LocalDensity.current.fontScale 获取该值,可以自由控制应用内文字的显示大小。