[关闭]
@946898963 2022-11-10T02:48:31.000000Z 字数 7866 阅读 1384

安卓屏幕的尺寸信息

Android适配


几个概念

1. 像素

屏幕上的点,我们通常所说的分辨率如480X800就是指的像素。

在设计领域中,像素是用来计算数码影像的最小单位。计算机中显示的图像并非连续的线条组成,而是由许多肉眼看不见的小点组成。如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小点所组成,这些小点就是构成影像的最小单位“像素”。由于是最小的独立显示单位,px均为整数,不会出现0.5px的情况。

2. 英寸

是屏幕的物理尺寸。每英寸等于2.54厘米。例如我们经常说的手机屏幕大小有,5(英)寸、4(英)寸就是指这个单位。

3. 分辨率

分辨率就是手机屏幕的像素点数,一般描述成屏幕的“宽×高”,安卓手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素,在高度方向有1280个像素。

手机目前常见的分辨率:

4:3

项目 分辨率
VGA 640*480
QVGA 320*240
HVGA 480*320
SVGA 800*600

5:3

项目 分辨率
WVGA 800*480

16:9

项目 分辨率
FWVGA 854*480 Full Wide VGA
HD 1920*1080 High Definition
QHD 960*540
720p 1280*720 标清
1080p 1920*1080 高清

4.屏幕大小

屏幕大小是手机对角线的物理尺寸,以英寸(inch)为单位。比如某某手机为“5寸大屏手机”,就是指对角线的尺寸,5寸×2.54厘米/寸=12.7厘米。

5. 每英寸的像素数量

(dpi,dots per inch;或PPI,pixels per inch)。从英文顾名思义,就是每英寸的像素点数,数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920,屏幕大小是5英寸,根据勾股定理,我们得出对角线的像素数大约是2203,那么用2203除以5就是此屏幕的密度了,计算结果是440。440dpi的屏幕已经相当细腻了。

DPI/PPI

  1. DPI = Dots Per Inch
  2. PPI = Pixel Per Inch

两个参数的区别就在于Dot和Pixel的区别,dot值的是显示器上每一个物理的点,而pixel指的是屏幕分辨率中的最小单位。这个两个难道会不一样么?会!当一个像素需要多于一个屏幕上的物理点来显示的时候dot就跟pixel不一样了。这个有另一个叫法叫做dppx(dot per pixel),即每个像素中有多少个点。大部分的显示器中一个像素即一个点,但目前一些比较好的屏幕和一些手机屏幕中dppx会大于1。比如说Mac Retina,iPhone,HTC One等。

总结来说我们一般针对Android手机说的 dpi 和 ppi 是等价的

分辨率对应DPI:

项目 DPI
HVGA mdpi
WVGA hdpi
FWVGA hdpi
QHD hdpi
720P xhdpi
1080P xxhdpi

此处输入图片的描述

实际密度与系统密度

“实际密度”就是我们自己算出来的密度,这个密度代表了屏幕真实的细腻程度,如上述例子中的440dpi就是实际密度,说明这块屏幕每寸有440个像素。5英寸1080×1920的屏幕密度是440,而相同分辨率的4.5英寸屏幕密度是490。如此看来,屏幕密度将会出现很多数值,呈现严重的碎片化。而密度又是安卓屏幕将界面进行缩放显示的依据,那么安卓是如何适配这么多屏幕的呢?

其实,每部安卓手机屏幕都有一个初始的固定密度,这些数值是120、160、240、320、480,我们权且称为“系统密度”,系统密度是出厂预置的。大家发现规律没有?相隔数值之间是2倍的关系。一般情况下,240×320的屏幕是低密度120dpi,即ldpi;320×480的屏幕是中密度160dpi,即mdpi;480×800的屏幕是高密度240dpi,即hdpi;720×1280的屏幕是超高密度320dpi,即xhdpi;1080×1920的屏幕是超超高密度480dpi,即xxhdpi。

安卓对界面元素进行缩放的比例依据正是系统密度,而不是实际密度。

(得到实际密度以后,一般会选择一个最近的密度作为系统密度,系统密度是出厂预置的,如440dpi的系统密度就是和他最接近的480dpi,如果是330dpi的手机他的系统密度就是320dpi。但是,我感觉现在很多手机不一定会选择这些值作为系统密度,而是选择实际的dpi作为系统密度,这就导致了很多手机的dpi也不是在这些值内。)

此处输入图片的描述

一个重要的单位dp

dp也可写为dip,即density-independent pixel。你可以想象dp更类似一个物理尺寸,比如一张宽和高均为100dp的图片在320×480和480×800的手机上“看起来”一样大。而实际上,它们的像素值并不一样。dp正是这样一个尺寸,不管这个屏幕的密度是多少,屏幕上相同dp大小的元素看起来始终差不多大。

另外,文字尺寸使用sp,即scale-independentpixel的缩写,这样,当你在系统设置里调节字号大小时,应用中的文字也会随之变大变小。

此处输入图片的描述

dp与px的转换

在安卓中,系统密度为160dpi的中密度手机屏幕为基准屏幕,即320×480的手机屏幕,在这个屏幕中,1dp=1px。

100dp在320×480(mdpi,160dpi)中是100px。那么100dp在480×800(hdpi,240dpi)的手机上是多少px呢?我们知道100dp在两个手机上看起来差不多大,根据160与240的比例关系,我们可以知道,在480×800中,100dp实际覆盖了150px。因此,如果你为mdpi手机提供了一张100px的图片,这张图片在hdpi手机上就会拉伸至150px,但是他们都是100dp。

中密度和高密度的缩放比例似乎可以不通过160dpi和240dpi计算,而通过320px和480px也可以算出。但是按照宽度计算缩放比例不适用于超高密度xhdpi和超超高密度xxhdpi了。即720×1280中1dp是多少px呢?如果用720/320,你会得出1dp=2.25px,实际这样算出来是不对的。dp与px的换算要以系统密度为准,720×1280的系统密度为320,320×480的系统密度为160,320/160=2,那么在720×1280中,1dp=2px。同理,在1080×1920中,1dp=3px。

大家可以记住下面这个比例,dp与px的换算就十分easy啦!

ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12,我们发现,相隔数字之间还是2倍的关系。计算的时候,以mdpi为基准。比如在720×1280(xhdpi)中,1dp等于多少px呢?mdpi是4,xhdpi是8,2倍的关系,即1dp=2px。反着计算更重要,比如你用PhotoShop在720×1280的画布中制作了界面效果图,两个元素的间距是20px,那要标注多少dp呢?2倍的关系,那就是10dp!

此处输入图片的描述

此处输入图片的描述

当安卓系统字号设为“普通”时,sp与px的尺寸换算和dp与px是一样的。比如某个文字大小在720×1280的PS画布中是24px,那么告诉工程师,这个文字大小是12sp。

density和dpi

density是屏幕密度,density和dpi的关系为 density = dpi/160,这个值在代码中经常遇到。

几个资源的文件夹

新建一个Android项目后应该可以看到很多drawable文件夹,分别对应不同的dpi:

  • drawable-ldpi (dpi=120, density=0.75)

  • drawable-mdpi (dpi=160, density=1)

  • drawable-hdpi (dpi=240, density=1.5)

  • drawable-xhdpi (dpi=320, density=2)

  • drawable-xxhdpi (dpi=480, density=3)

市面上的一些Android教程大多都是教的是为每种dpi都出一套图片资源,这个固然是一种解决办法,但同时也是一种非常笨的方法,为美工或者设计增加了不少的工作量不说,同时也会让你的apk包变的很大。那么有没有什么好的方法既能保证屏幕适配,又可以最小占用设计资源,同时最好又只使用一套dpi的图片资源呢?下面就来讲解下项目中总结出来的这个方法。

首先必须清楚一个自动渲染的概念,Android SDK会自动根据屏幕尺寸选择对应的资源文件进行渲染,如SDK检测到你手机dpi是160的话会优先到drawable-mdpi文件夹下找对应的图片资源,注意只是优先,假设你手机dpi是160,但是你只在xhpdi文件夹下有对应的图片资源文件,程序一样可以正常运行。所以理论上来说只需要提供一种规格的图片资源就ok了,如果只提供ldpi规格的图片,对于大分辨率的手机如果把图片放大就会不清晰,所以需要提供一套你需要支持的最大dpi的图片,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。

以应用图标为例,xhdpi中的图标大小是96px,如果要单独给mdpi提供图标,那么这个图标大小是48px,放到drawable-mdpi的资源文件夹中。各个资源文件夹中的图片尺寸同样符合ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的规律。

此处输入图片的描述

如果你把一个高2px的分割线素材做成了9.png图片,你想让细线在不同密度中都是2px,而不被安卓根据密度进行缩放,怎么办?你可以把这个分割线素材放到drawable-nodpi中,这个资源文件夹中的图片,将按照实际像素大小进行显示,而不会被安卓根据密度进行缩放。即在mdpi中细线是2px(2dp),在xhdpi中细线是2px(1dp)。

建议在xxdhpi中作图

上面说了只需要提供一套大的dpi的图片就ok了,现在市面手机分辨率最大可达到1080X1920的分辨率,而且普及率很高,所以目前来看xxhpdi规则的图片成为了首选。

在1080×1920中做了图片,开发人员放到drawable-xxhdpi的资源文件夹中,这样才可以显示正确。可以测试一下应用在低端手机上运行是否流畅,如果比较卡顿,可以根据需要提供部分mdpi的图片素材,因为xxhdpi中的图片运行在mdpi的手机上会比较占内存。

设计资源紧张怎么办?

在现在的App开发中,基本都会有iOS和Android版本,有些公司为了保持App不同版本的体验交互一致,还有些公司的设计资源可能比较紧张,这些情况下iOS和Android版本基本是一个设计师主导,而大多数情况下设计师可能更会以iPhone手机为基础进行设计,包括后期的切图之类的。这个时候身为Android开发人员你是否还要求设计师单独为Android端切一套图片资源呢?这会让你们的设计师崩溃的,下面就来告诉一个项目中总结的更棒的方法。

相信设计师们一般都会用最新的iPhone5(5s和5的尺寸以及分辨率都一样)来做原型设计,而iPhone5的屏幕分辨率为640X1164, 屏幕尺寸为4英寸,根据勾股定理(a^2 + b^2 = c^2)640^2+1164^2=1764496, 然后再对其开根号可求出屏幕对角线的分辨率为:1328,除以4可得出iphone5的dpi:1328/4≈332 可以看出iPhone5的屏幕的dpi约等于320, 刚好属于xhdpi,所以你可以很自豪的像你们的设计师说不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就ok了。

相关代码

如何判断手机是hdpi,xhdpi,还是xxhdpi

代码判断:

  1. density = getResources().getDisplayMetrics().density;
  2. // return 0.75 if it's LDPI
  3. // return 1.0 if it's MDPI
  4. // return 1.5 if it's HDPI
  5. // return 2.0 if it's XHDPI
  6. // return 3.0 if it's XXHDPI
  7. // return 4.0 if it's XXXHDPI
  1. switch (getResources().getDisplayMetrics().densityDpi) {
  2. case DisplayMetrics.DENSITY_LOW:
  3. // ...
  4. break;
  5. case DisplayMetrics.DENSITY_MEDIUM:
  6. // ...
  7. break;
  8. case DisplayMetrics.DENSITY_HIGH:
  9. // ...
  10. break;
  11. case DisplayMetrics.DENSITY_XHIGH:
  12. // ...
  13. break;
  14. }

使用adb指令

Windows环境下在Android Studio的Terminal里输入:

  1. adb shell dumpsys | findStr mBaseDisplay

Mac 把"findStr"替换成"grep"即可:

  1. adb shell dumpsys | grep mBaseDisplay

此处输入图片的描述

"density 320"对应DENSITY_XHIGH,"density 480"对应DENSITY_XXHIGH。

DisplayMetrics

Android中的DisplayMetrics这个类描述了关于显示的各种信息,可以利用它查看设备的状态,上述关于屏幕密度的标准的常量也是从这个类中看到的。

DisplayMetrics的toString()方法如下:

  1. @Override
  2. public String toString() {
  3. return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
  4. ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
  5. ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
  6. }

其中各个变量解释如下:

  1. /**
  2. * The absolute width of the display in pixels.
  3. */
  4. public int widthPixels;
  5. /**
  6. * The absolute height of the display in pixels.
  7. */
  8. public int heightPixels;
  9. /**
  10. * The logical density of the display. This is a scaling factor for the
  11. * Density Independent Pixel unit, where one DIP is one pixel on an
  12. * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
  13. * providing the baseline of the system's display. Thus on a 160dpi screen
  14. * this density value will be 1; on a 120 dpi screen it would be .75; etc.
  15. *
  16. * <p>This value does not exactly follow the real screen size (as given by
  17. * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
  18. * the overall UI in steps based on gross changes in the display dpi. For
  19. * example, a 240x320 screen will have a density of 1 even if its width is
  20. * 1.8", 1.3", etc. However, if the screen resolution is increased to
  21. * 320x480 but the screen size remained 1.5"x2" then the density would be
  22. * increased (probably to 1.5).
  23. *
  24. * @see #DENSITY_DEFAULT
  25. */
  26. public float density;
  27. /**
  28. * The screen density expressed as dots-per-inch. May be either
  29. * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
  30. */
  31. public int densityDpi;
  32. /**
  33. * A scaling factor for fonts displayed on the display. This is the same
  34. * as {@link #density}, except that it may be adjusted in smaller
  35. * increments at runtime based on a user preference for the font size.
  36. */
  37. public float scaledDensity;
  38. /**
  39. * The exact physical pixels per inch of the screen in the X dimension.
  40. */
  41. public float xdpi;
  42. /**
  43. * The exact physical pixels per inch of the screen in the Y dimension.
  44. */
  45. public float ydpi;

尺寸单位转换

  1. public class DimenUtils {
  2. public static int sp2px(Context context, float spValue) {
  3. float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  4. return (int) (spValue * fontScale + 0.5f);
  5. }
  6. public static int px2sp(Context context, float pxValue) {
  7. float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  8. return (int) (pxValue / fontScale + 0.5f);
  9. }
  10. public static int dip2px(Context context, int dipValue) {
  11. final float scale = context.getResources().getDisplayMetrics().density;
  12. return (int) (dipValue * scale + 0.5f);
  13. }
  14. public static int px2dip(Context context, float pxValue) {
  15. final float scale = context.getResources().getDisplayMetrics().density;
  16. return (int) (pxValue / scale + 0.5f);
  17. }
  18. }

参考链接:

安卓屏幕分辨率及UI尺寸详解&&《Android群英传 P107》

Android常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )尺寸单位转换和屏幕适配相关

关于Android xxhdpi xhdpi hdpi的理解(有关于设置margin和padding的适配问题)

Android hdpi,xhdpi,xxhdpi一些你没注意到的事

彻底理解ldpi、mdpi、hdpi、xhdpi、xxhdpi,图片到底放在哪个目录

安卓分辨率的相关知识

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注