专栏首页闷骚的程序员Android UI 开发里的尺寸单位理解

Android UI 开发里的尺寸单位理解

在学习 Android UI 开发的初期,经常被一些常用概念如 dp、sp 和它们与 px 的换算等虐,要避免被虐,最好的方法当然是知其所以然,再见到它们就胸中有料心不慌了。

背景知识

参考 http://developer.android.com/guide/practices/screens_support.html#terms

  1. 屏幕大小(Screen size) 屏幕对角线的实际物理大小。通常以英寸(inch)为单位。
  2. 屏幕密度(Screen density) 每英寸上的像素个数。通常被称作多少 dpi(dots per inch)或多少 ppi(pixels per inch)。 比如,LG Nexus 5 的屏幕尺寸为 4.95 英寸,分辨率为 1920*1080,则它的对角线上的像素数为 sqrt((sqr(1920)+sqr(1080)),所以它的屏幕密度为 sqrt((sqr(1920)+sqr(1080))/4.95=445.03,约为 445dpi。
  3. 分辨率(Resolution) 屏幕上的物理像素个数。 比如 LG Nexus 5 的分辨率为 1920*1080,这里的 1920 和 1080 就是屏幕长和宽上的像素个数。

尺寸

参考 http://developer.android.com/guide/topics/resources/more-resources.html#Dimension

  1. dp(Density-independent Pixels) 在不同大小、密度和分辨率的屏幕上的物理大小都近似相等的虚拟尺寸单位。 约为 1/160 英寸(为什么是约为?稍后讲解)。
  2. sp(Scale-independent Pixels) 基于首选字体大小的缩放像素。 与 dp 类似,但是会根据用户的首选字体大小缩放。
  3. pt(Points) 1/72 英寸。
  4. px(Pixels) 像素。
  5. mm(Millimeters) 毫米。
  6. in(Inches) 英寸,约 2.539999918 厘米。

换算

dp 转 px

参考http://developer.android.com/guide/practices/screens_support.html#dips-pels

为了简单起见,Android 将屏幕密度概括为 6 种:

  • ldpi(low) ~120dpi
  • mdpi(medium) ~160dpi
  • hdpi(high) ~240dpi
  • xhdpi(extra-high) ~320dpi
  • xxhdpi(extra-extra-high) ~480dpi
  • xxxhdpi(extra-extra-extra-high) ~640dpi

但是并非表示所有 Android 手机只有这几个屏幕密度,比如上面举例的 LG Nexus 5 的屏幕密度是 445dpi,近似地归于 xxhdpi,Android 在内部进行 dp 到 px 的换算时将采用 480dpi 而非 445dpi

简而言之,dp 数 x 换算成 px 数 y 的公式:

// 向上取整
y = x * generalizedDensity / 160

这里的 generalizedDensity 就是以上 6 种中的一个值,比如 LG Nexus 5 的实际屏幕密度为 445dpi,但是归于 xxhdpi,所以它的 generalizedDensity 就是 480dpi。

官方文档给出的转换 dp 到 px 的代码示例为:

// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;

// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

// Use mGestureThreshold as a distance in pixels...

在 mdpi(160dpi)上 1dp=1px(还记得前面讲过的 1dp 约为 1/160 英寸吗?在 160dpi 的屏幕上,1px=1/160 英寸),这里的getResources().getDisplayMetrics().density实际上就等于我们的generalizedDensity / 160,表示将 dp 转换为 px 的一个转换因子。

然后来理解一下为何 dp 是约为 1/160 英寸。

还是以 LG Nexus 5 举例,比如 160dp,若在一个屏幕密度恰好是 480dpi 的机器上,那它会是准确的 1 英寸,但是 LG Nexus 5 的屏幕密度是 445dpi,根据上面的公式计算得出:160dp = 160 * 480 / 160 px = 480px,则它的实际显示尺寸为 480/445=1.07865 英寸。所以原因是dp 换算成 px 是使用 Android 概括的六种屏幕密度之一,而非实际屏幕密度,所以在不同的手机上相同数量的 dp 显示尺寸会有轻微差异。

sp 转 px

http://developer.android.com/reference/android/util/DisplayMetrics.html#scaledDensity中可以看到scaledDensity就是控制字体尺寸的缩放因子。于是猜想 sp 数 x 换算成 px 数 y 的公式:

y = x * scaledDensity

这里的 scaledDensity 获取方式为getResources().getDisplayMetrics().scaledDensity

这个猜想是否正确呢?看看下面一张图就明白啦!(Nexus 4 模拟器截图)

根据分辨率和屏幕密度求屏幕尺寸

使用 adb 命令 adb shell wm size 可以得到设备分辨率,adb shell wm density 可以得到设备屏幕密度,但貌似没有办法直接得到屏幕尺寸,只能拿到这两个数据之后换算。

公式:

sqrt(sqr(width)+sqr(height))/density

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从 am start 的 --user 参数说到 Android 多用户

    本文的讨论围绕一个 java.lang.SecurityException 展开,异常的关键词是权限 android.permission.INTERACT_A...

    mzlogin
  • 让 Tapd 的源码关联功能支持 Gitee 平台

    Tapd 是腾讯提供的越来越完善的项目管理工具,Gitee 是国内相对比较稳的代码托管平台。本文记录了让 Tapd 的源码关联功能支持 Gitee 平台的方法,...

    mzlogin
  • Python 核心编程中文第二版课后练习 3.8 答案

    3-1 变量在第一次被赋值时自动声明。在赋值时解释器会根据语法和右侧的操作数来决定新对象的类型。

    mzlogin
  • Hadoop - YARN Introduce

    ResourceManager(RM)是一个全局的资源管理器,负责整个系统的资源管理和分配,主要包括两个组件,即调度器(Scheduler)和应用程序管理器(A...

    mantou
  • 一起学并发编程 - 利用观察者模式监听线程状态

    在Java多线程下,我们需要知道当前执行线程的状态是什么比如 运行, 关闭, 异常等状态的通知,而且不仅仅是更新当前页面。

    battcn
  • Codeforces Round #313 (Div. 2)

    大半年没有打Codeforces , 昨天开始恢复打Codeforces, 简直是, 欲语泪先流啊。

    若羽
  • 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)--B-杨老师的游戏

    Enterprise_
  • 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)--B-杨老师的游戏

    Enterprise_
  • Spring Boot Actuator监控端点小结

    初识Actuator 在Spring Boot的众多Starter POMs中有一个特殊的模块,它不同于其他模块那样大多用于开发业务功能或是连接一些其他外部资源...

    程序猿DD
  • 开源托管站点大全

    landv

扫码关注云+社区

领取腾讯云代金券