1.先来看几个概念

  • 分辨率,像 1920x1080
  • 屏幕像素密度:屏幕每英寸所包含的像素数
  • dpi:(Dots Per Inch,每英寸点数)一种度量单位

怎么根据分辨率和屏幕尺寸计算屏幕密度?√(1920^2+1080^2)=2203

android的屏幕密度 屏幕密度dpi_像素点

计算屏幕密度.png

那440dpi在android中是什么样的概念呢?

android的屏幕密度 屏幕密度dpi_像素点_02

谷歌官方文档中对于密度的分类.png

属于xxhdpi这一分类 ,那么其运行时加载的图片也是xxhdpi文件夹下的。

2.接下来看px与dp还有dip的关系

  • dp其实就是dip:设备独立像素(又称设备无关像素 Device Independent Pixels 、密度独立性 Density ndependent或设备独立像素,简称DIP或DP)。
    dp也是谷歌推荐的android开发中使用单位。
  • px:像素

一般UI拿过来的图就是px标注的,然后会告诉你做图时所用的尺寸是多大的,如1334x750,4.7寸的屏幕

android的屏幕密度 屏幕密度dpi_像素点_03

image.png

我们该怎么把px转为dp写在android的布局文件中呢?

  1. 先计算UI所给图纸的密度,1334x1334+750x750=2342056
    2342056 开根号大概为 1530
    1530/4.7 = 325 dpi
  2. 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 颗像素(发光点)。

android的屏幕密度 屏幕密度dpi_android的屏幕密度_04

分辨率、像素和屏幕尺寸

PPI 说的是像素密度,而分辨率说的是块屏幕的像素尺寸,譬如说 1334*750 就是 iPhone(6~7)的分辨率,说 iPhone(6~7)的分辨率是 326 是错误的表述,326 是它的像素密度,单位是 PPI。

询问别人一粒像素有多大是一个非常鸡贼的问题(小心面试遇到这样的题),虽然我们说像素是构成屏幕的发光的点,是物理的,但是像素在脱离了屏幕尺寸之后是没有大小可言的,你可以将 1920 * 1080 颗像素放到一台 40 寸的小米电视机里面,也可以将同样多的像素全部塞到一台 5.5 寸的 iPhone7 Plus 手机里面去,那么对于 40 寸的电视而言,每个像素颗粒当然会大于 5.5 寸的手机的像素。

android的屏幕密度 屏幕密度dpi_android_05

所以光看屏幕的分辨率对于设计师来说是不具备多少实际意义的,通过分辨率计算得出的像素密度(PPI)才是设计师要关心的问题,我们通过屏幕分辨率和屏幕尺寸就能计算出屏幕的像素密度的。

再次使用 iPhone(6~7)作为例子。我们知道该屏幕的横向物理尺寸为 2.3 英寸 ,且横向具有 750 颗像素,根据下面的公式,我们能够算出 iPhone(6~7)的屏幕是 326 PPI,意为每寸存在 326 颗像素。

android的屏幕密度 屏幕密度dpi_缩放_06

其实不论我们怎么除,计算得出来的像素密度(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 英寸的屏幕,所以这个色块在屏幕上面看起来就“长大了”一倍。

android的屏幕密度 屏幕密度dpi_像素点_07

总结

  • 像素本身没有尺寸,你可以将 1920 * 1080 颗像素放到一台 40 寸的小米电视机里面,也可以将同样多的像素全部塞到一台 5.5 寸的 iPhone7 Plus 手机里面去。
  • 只有跟屏幕尺寸一起的时候,谈论像素才有意义,因为我们能够算出该屏幕的 PPI。
  • DPI 跟 PPI 虽然概念相近,但是我奉劝你还是不要拿着他们俩混用,虽然可能好多人告诉你这样没啥关系。
  • 在设计过程中,我们并不见得真的要去计算各种东西的实际尺寸,但是对于原理的把握能让你心里有个底,或许就是我们常说的「意识」。别以为每个人的屏幕上显示的都会跟你屏幕上显示的是一样的。