我从Web前端切换到Android开发,一件事很难理解的是Android屏幕的密度如何影响单位的使用。对于Web,我主要使用像素,em
s(元素字体大小的计算值)和rem
s(root元素字体大小的计算值)。
所以,我想写一篇有关此主题的博客文章,因为我敢打赌我不是唯一的一个。让我们首先看一下与密度无关的像素,它们是什么以及为什么使用它们。之后,让我们讨论它们与像素之间的转换。我故意省略了本博客文章中与比例无关的像素,以专注于密度与密度无关的像素。
什么是密度独立的像素?
Android设备具有不同尺寸的屏幕。它们在屏幕上也具有不同的像素尺寸 - 因此,在屏幕上,像素的宽度有一定数量的像素,与具有更多像素的像素相比,屏幕上的像素尺寸不同。这是因为一个屏幕可能仅适合相同的物理空间中的320像素,而另一个适合640像素。
密度与密度无关的像素是为了解决这些差异所致的问题。 Android文档通过以下方式定义了与密度无关的像素:
为了在屏幕上保留UI的可见尺寸,请使用密度无关的像素(DP)作为测量单位来设计UI。一个DP是一个虚拟像素单元,在中密度屏幕(160 dpi或“基线”密度)上大致等于一个像素。 Android将此值转换为彼此密度的适当数量的真实像素。
来源:Support different pixel densities - Android Developers
让我们下一步看看真实像素和密度无关的像素之间的转换。
像素和密度无关的像素之间的转换
在多种情况下,我们需要从独立于设备的像素到像素的转换,反之亦然。让我们看一下如何转换它们 - 首先在可组合组件的范围内,然后在其他情况下。
组合组件
使用JetPack组成,LocalDensity
有助于像素和密度无关的像素之间的转换。 LocalDensity
是内置组成的当地人之一,它提供了一个可用于像素和密度无关像素的转换以及与比例无关的像素之间的Density
。
让我们看一下如何在可组合组件中使用它。首先,从像素到独立于设备的像素:
@Composable
fun PxToDp(widthInPx: Int) {
val density = LocalDensity.current
val widthInDp = with (density) { widthInPx.toDp() }
...
}
,反之亦然:
@Composable
fun DpToPx(widthInDp: Int) {
val density = LocalDensity.current
val widthInPx = with (density) { widthInDp.toPx() }
...
}
两个示例都利用Kotlin的with
-Scope函数。在LocalDensity,
提供的Density
范围内,可以使用用于转换的扩展功能,我们可以使用它们。
其他情况
不使用JetPack组合和/或LocalDensity
是不可用的,例如,您可以编写自己的扩展功能以进行转换。这是一个具有扩展功能的Float
-datatype的示例:
fun Float.toDp() =
(this / Resources.getSystem().displayMetrics.density)
fun Float.toPx() =
(this * Resources.getSystem().displayMetrics.density)
在两个功能中,设备的屏幕密度都是从Resources.getSystem().displayMetrics.density
获取的。对于像素到DP转换,像素值由其划分,对于DP-TO-PIXER代码,DP值乘以它。
包起来
在这篇博客文章中,我们讨论了与设备无关的像素。我们还研究了如何将它们转换为像素和后退。在许多情况下,例如在布局上定位元素时,这些转换可能很有用。
您是否有任何需要在之间转换时的例子?还是比您希望的要复杂的时候?分享您的想法!