1.先来看几个概念
- 分辨率,像 1920x1080
- 屏幕像素密度:屏幕每英寸所包含的像素数
- dpi:(Dots Per Inch,每英寸点数)一种度量单位
怎么根据分辨率和屏幕尺寸计算屏幕密度?√(1920^2+1080^2)=2203
计算屏幕密度.png
那440dpi在android中是什么样的概念呢?
谷歌官方文档中对于密度的分类.png
属于xxhdpi这一分类 ,那么其运行时加载的图片也是xxhdpi文件夹下的。
2.接下来看px与dp还有dip的关系
- dp其实就是dip:设备独立像素(又称设备无关像素 Device Independent Pixels 、密度独立性 Density ndependent或设备独立像素,简称DIP或DP)。
dp也是谷歌推荐的android开发中使用单位。 - px:像素
一般UI拿过来的图就是px标注的,然后会告诉你做图时所用的尺寸是多大的,如1334x750,4.7寸的屏幕
image.png
我们该怎么把px转为dp写在android的布局文件中呢?
- 先计算UI所给图纸的密度,1334x1334+750x750=2342056
2342056 开根号大概为 1530
1530/4.7 = 325 dpi - 325/160 = 2.03 (160相当于一个标准dpi,是google给定的值,我们所计算的dpi都会与其进行比较)
如图上一个控件是高80px,那 80/2.03 大概40dp,我们一般就在布局文件设置40dp
Android DisplayMetrics中参数的意思: * widthPixels:宽度 显示的数值是1080,就是说屏幕的宽度是1080px * heightPixels:高度 * densityDpi:密度(像素点每英寸密度)单位英寸下的所有点,440dpi * density:密度比值(密度/标准密度,即480/160=3),一个显示单位下可以容纳多少个点(相对160/1的密度)(显示单位:如所有显示规格的手机都将显示单位设置成160dpi的个数,如480*320份,这一份显示单位里,有的数字,就是密度比值。假如160dpi的显示器,一个显示单位里有1个像素,那density=3的意思就是,这种手机一个显示单位里有3个像素) * scaledDensity:同density,用于文字缩放的计算也就是sp,随字体缩放而变化,增加或缩小要显示的像素点数 * xDpi:水平方向的真实密度,水平方向上1inch实际上容纳的点的数量 * yDpi:垂直方向的真实密度
其实你妹的Android就不能搞个比较统一的度量来统一设计和开发吗,老是算算算,适配适配适配,就不能多做一步吗,唉,还是留给我们这些程序猿来搞吧,不然他们都做了,我们哪来的机会
dpi = dots per inch 每英寸像素点个数 (绝对密度 absolutely density)
px = pixel 像素点
dip = device independence pixel = dp 设备独立像素
绝对像素密度 absolutely density dpi = ⎷(长^2+宽^2)/对角英寸长
标准像素密度 = 160dpi
相对像素密度 (relative density) =(absolutely density) dpi/160dpi = float
dp(dip) = px / ((absolutely density) dpi/160) = px / (relative density)
简单说就是 dp(dip) = px/相对密度
思考个问题:如果设计是一个大屏幕的,但是现在要在小屏幕上显示?
只是这个px数字和dip数字几乎一样,但是怎么显示,
还是Android系统会帮你具体计算好,需要显示几个px。且显示效果也是等比例一致。
其实设计师也不会管你这么多,是多少dp(dip),他只会管给多少px,
dpi是根据不同手机来定的,具体Android工程师要设置多少dip就是你自己的事情了,计算吧猴子们~
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.res.Configuration;
import android.util.DisplayMetrics;
import androidx.annotation.NonNull;
/**
* 一种极低成本的Android屏幕适配方式
* 字节跳动技术团队
* https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA
* <p>
* 当然以下代码只是以设计图宽360dp去适配的,如果要以高维度适配,可以再扩展下代码即可。
*
* dpi = dots per inch 每英寸像素点个数
*
* px = pixel 像素点
* dip = device independence pixel = dp 设备独立像素
*
* 斜边
* 像素密度 density dpi = ⎷(长^2+宽^2)/对角英寸长
* 标准像素密度 = 160dpi
* 缩放因子 scale = density dpi/160dpi = float
* dp(dip) = px / (density dpi/160) = px / scale
*
* dpi,分辨率,屏幕尺寸,dp,px,dip
* https://www.jianshu.com/p/a585841282a8
*
*
* widthPixels:宽度 显示的数值是1080,就是说屏幕的宽度是1080px
* heightPixels:高度
* densityDpi:密度(像素点每英寸密度)单位英寸下的所有点,440dpi
* density:密度比值(密度/标准密度,即480/160=3),一个显示单位下可以容纳多少个点(相对160/1的密度)
* scaledDensity:同density,用于文字缩放的计算也就是sp
* xDpi:水平方向的真实密度,水平方向上1inch实际上容纳的点的数量
* yDpi:垂直方向的真实密度
* ————————————————
* 原文链接:
*/
public class DisplayUtil {
private static float sNonCompatDensity;//密度
private static float sNonCompatScaleDensity;//缩放密度
private static void setCustomDensity(@NonNull Activity activity,
@NonNull Application application) {
//显示矩阵
final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
if (sNonCompatDensity == 0) {
//相对密度,根据手机而定,手机定了,这个就定了
sNonCompatDensity = appDisplayMetrics.density;
//缩放密度
sNonCompatScaleDensity = appDisplayMetrics.scaledDensity;
//注册监听字体大小设置的改变
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
//得到设置字体大小改变后的,字体缩放密度
sNonCompatScaleDensity
= application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
/**
* 下面假设设计图宽度是360dp(1080px),以宽维度来适配。
* 那么适配后的 density = 设备真实宽(单位px) / 360,
* 接下来只需要把我们计算好的 density 在系统中修改下即可
*/
//得到设计图的 相对密度
final float targetDensity = appDisplayMetrics.widthPixels / 360;
//得到设计图的 缩放密度
final float targetScaledDensity = targetDensity * (sNonCompatScaleDensity / sNonCompatDensity);
// 绝对密度dpi
final int targetDensityDpi = (int) (160 * targetDensity);
/**
* 这样获得这三个值,就可以让屏幕显示效果一致了???
* 通过将1080的屏幕设置为一个标准屏幕,所以可以得到目前已知的大部分屏幕的等比例显示
*/
//设置给app全部显示参数
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.scaledDensity = targetScaledDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
//设置给每个Activity显示参数
final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
}
}
PS:再区分一个概念,dpi和ppi
DPI 和 PPI 是什么?
一个是对角线显示像素密度,一个是宽度像素密度。
DPI 是英文 Dots(点) Per Inch 的缩写,在最早的时候,这个单位是用来描述打印机的性能的,意思就是这台打印机最多能用多少个墨点来打印一寸的内容。目前市面上常见的家用黑白打印机普遍都去到了 600 * 600 dpi, 而家用彩色照片打印机则能去到 5760 * 1440 dpi。DPI 越高,每英寸内的墨点就越多,你打印出来的东西就会越清晰锐利。
PPI 是英文 Pixels Per Inch 的缩写,意味每寸能容纳多少颗像素,用于描述屏幕的像素密度。我们上面提到的印刷物以无数多的墨点来构成图像,而屏幕同样也是以一定数量的发光点来构成图像。见过街上那些走红字的 LED 显示屏么?上面的那一颗颗的 LED 灯就是这块屏幕的发光点,我们使用的 MacBook 的 Retina 显示屏的原理也跟这些看起来十分粗糙的走红字显示屏是一样的,只不过 Retina 显示屏的发光点密度非常高,人眼已经看不出来颗粒感而已。对于屏幕来说 PPI 是用于描述每英寸发光点数量的,它表明了一块屏幕发光点密度的高低,这些发光点我们更常称之为像素,一块屏幕宽高有几寸是在生产的时候就被定好的,而宽高各能容纳下多少颗像素,也是在生产的时候就被定好的,所以我们所说的 PPI 可以说是一个物理单位。
简单举个例子吧,我们手头上的 iPhone(6~7) 宽为 2.3 英寸,高为 4.1 英寸,根据勾股定理得出这块屏幕的尺寸(屏幕对角线距离)是 4.7 英寸。同时,iPhone(6~7)屏幕宽(每行)有 750 个像素(发光点),高(每竖)有 1334 颗像素(发光点)。
分辨率、像素和屏幕尺寸
PPI 说的是像素密度,而分辨率说的是块屏幕的像素尺寸,譬如说 1334*750 就是 iPhone(6~7)的分辨率,说 iPhone(6~7)的分辨率是 326 是错误的表述,326 是它的像素密度,单位是 PPI。
询问别人一粒像素有多大是一个非常鸡贼的问题(小心面试遇到这样的题),虽然我们说像素是构成屏幕的发光的点,是物理的,但是像素在脱离了屏幕尺寸之后是没有大小可言的,你可以将 1920 * 1080 颗像素放到一台 40 寸的小米电视机里面,也可以将同样多的像素全部塞到一台 5.5 寸的 iPhone7 Plus 手机里面去,那么对于 40 寸的电视而言,每个像素颗粒当然会大于 5.5 寸的手机的像素。
所以光看屏幕的分辨率对于设计师来说是不具备多少实际意义的,通过分辨率计算得出的像素密度(PPI)才是设计师要关心的问题,我们通过屏幕分辨率和屏幕尺寸就能计算出屏幕的像素密度的。
再次使用 iPhone(6~7)作为例子。我们知道该屏幕的横向物理尺寸为 2.3 英寸 ,且横向具有 750 颗像素,根据下面的公式,我们能够算出 iPhone(6~7)的屏幕是 326 PPI,意为每寸存在 326 颗像素。
其实不论我们怎么除,计算得出来的像素密度(PPI)都会是这个数,宽存在像素除以宽物理长度,高存在像素除以高物理长度,得数都接近于 326。
对设计会造成什么样的影响
一块 326*326px 的正方形色块在一台 iPhone 7 上面展现出来的物理尺寸将会会是 1*1 英寸。这是因为该屏幕每英寸能容纳 326 颗像素,所以 326px 凑在一起刚好就是 1 英寸。假设我们能将 iPhone 7 手机屏幕 PPI 调低 50% 变为 163,色块还是 326*326px,这个色块的物理尺寸会变成 2*2 英寸,同样多的像素,看起来却大了一倍。
因为我们的色块是 326*326px 大小的,而这台 163PPI 的假 iPhone 7 每英寸上面只有 163 颗像素,为了要展示 326*326px 的色块,它就要多用 1 英寸的屏幕,所以这个色块在屏幕上面看起来就“长大了”一倍。
总结
- 像素本身没有尺寸,你可以将 1920 * 1080 颗像素放到一台 40 寸的小米电视机里面,也可以将同样多的像素全部塞到一台 5.5 寸的 iPhone7 Plus 手机里面去。
- 只有跟屏幕尺寸一起的时候,谈论像素才有意义,因为我们能够算出该屏幕的 PPI。
- DPI 跟 PPI 虽然概念相近,但是我奉劝你还是不要拿着他们俩混用,虽然可能好多人告诉你这样没啥关系。
- 在设计过程中,我们并不见得真的要去计算各种东西的实际尺寸,但是对于原理的把握能让你心里有个底,或许就是我们常说的「意识」。别以为每个人的屏幕上显示的都会跟你屏幕上显示的是一样的。