安卓里px、dip(dp)、sp、pt、in、mm的意义,及相互转换

 

今天碰巧看见了这个函数,是将传进来的值根据不同选项转化为最底层的像素,然后传出。

那么不妨来自己来探索下安卓里px、dip(dp)、sp、pt、in、mm到底是什么吧

 

public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
    {
        switch (unit) {
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP:
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }

 

 

 

介绍

网上关于px、dip(dp)、sp、pt、in、mm的介绍已经有很多了,这里我就不多阐述了,下面就简单贴下谷歌对这些关键字的说明

    /** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
    public static final int COMPLEX_UNIT_PX = 0;//原始像素
    /** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent Pixels. */
    public static final int COMPLEX_UNIT_DIP = 1;//与设备无关的像素
    /** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */
    public static final int COMPLEX_UNIT_SP = 2;//缩放的像素
    /** {@link #TYPE_DIMENSION} complex unit: Value is in points. */
    public static final int COMPLEX_UNIT_PT = 3;//点数
    /** {@link #TYPE_DIMENSION} complex unit: Value is in inches. */
    public static final int COMPLEX_UNIT_IN = 4;//英寸
    /** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */
    public static final int COMPLEX_UNIT_MM = 5;//毫米

同时,这个函数里需要传进来一个DisplayMetrics对象,那么这个DisplayMetrics对象是什么么?

 

下面,还是来看下谷歌的大爷们对它的定义吧

/**
 * A structure describing general information about a display, such as its
 * size, density, and font scaling.
 * <p>To access the DisplayMetrics members, initialize an object like this:</p>
 * <pre> DisplayMetrics metrics = new DisplayMetrics();
 * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
 */
public class DisplayMetrics {


大致意思是一个描述手机显示屏信息的一个实体类,那里面保存的都是写啥信息呢?我们拿手机的分辨率数据来同获取到的DisplayMetrics实例来进行对比一番

 

 

 

可以很清晰的看见DisplayMetrics对象里的高度和宽度像素值就等于手机屏幕的真实尺寸

那么回到上面的转换函数,里面用了DisplayMetrics实例的三个值:density、scaledDensity、xdpi

这三个又是啥子呢?

 

相互之间的转换

老样子,看下谷歌大爷们是怎么定义这三个值得,以及值是怎么来的

density、scaledDensity、xdpi的定义

density

/**
     * The logical density of the display.  This is a scaling factor for the
     * Density Independent Pixel unit, where one DIP is one pixel on an
     * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), 
     * providing the baseline of the system's display. Thus on a 160dpi screen 
     * this density value will be 1; on a 120 dpi screen it would be .75; etc.
     *  
     * <p>This value does not exactly follow the real screen size (as given by 
     * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
     * the overall UI in steps based on gross changes in the display dpi.  For 
     * example, a 240x320 screen will have a density of 1 even if its width is 
     * 1.8", 1.3", etc. However, if the screen resolution is increased to 
     * 320x480 but the screen size remained 1.5"x2" then the density would be 
     * increased (probably to 1.5).
     *
     * @see #DENSITY_DEFAULT
     */
    public float density;

大致意思呢就是,这个值是一个缩放比例,在160dpi的屏幕上等于1,在120pdi的屏幕上就等于0.75,当然,这个值是谷歌定的,见下表

对应表
ldpi120dpi0.75
mdpi160dpi1
hdpi240dpi1.5
xhpi320dpi2


那么dpi又是什么呢?

dpi也是一种单位,代表一英寸(等于2.54厘米)里有多少像素点,如上面的举例240X320分辨率是1.5X2尺寸的屏幕,所以160dpi=240/1.5=320/2=X或Y轴的像素值/屏幕比

同时下面的注释也提到了xdpi和ydpi就是X轴和Y轴的dpi,当然,这两个的值都是一样的,对于上面的例子来讲都是160dpi

 

那么不妨来看下这次测试的红米note2的数据吧,从上图可知,数据为:

xdpi=ydpi=403(有些许小数点后的差异,暂时未深入了解为什么),那么我们用分辨率除以它们得到的scren比例值是:(1920/403):(1080/430)=4.764:2.680,即

X轴为4.764英寸,Y轴为2.680英寸,而红米note2某宝上是5.5英寸,而5.5≈根号下(X轴英寸的平方+Y轴英寸的平方),那么你应该想到了什么5.5英寸指的是什么得意



好吧,回到正题,看下一个变量

 

scaledDensity

 

/**
     * A scaling factor for fonts displayed on the display.  This is the same
     * as {@link #density}, except that it may be adjusted in smaller
     * increments at runtime based on a user preference for the font size.
     */
    public float scaledDensity;


也是一个缩放系数,和density有关,能更好的调节用户对字体大小的偏好

 

xdpi

同上

 

变量的值是怎么来的?

好吧,一开始我们就是获取了一个DisplayMetrics对象然后使用里面的值,但是里面的值是怎么赋值的呢?

下面是流程:

Context c = getContext();
r.getDisplayMetrics()
那么我们进r.getDisplayMetrics()里面去看
public DisplayMetrics getDisplayMetrics() {
        return mResourcesImpl.getDisplayMetrics();
    }
原来是用另一个对象的函数啊,那再进去看看
DisplayMetrics getDisplayMetrics() {
        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
        return mMetrics;
    }
返回的是一个当前类里面的变量值,让我们找找我们看看这个mMetrics是在哪里初始化的
public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
            @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments){}
哦,是在构造函数里,那看来我们的返回上一个类里面,看看mResourcesImpl这个对象是在哪里被初始化
private Resources() {
        this(null);

        final DisplayMetrics metrics = new DisplayMetrics();
        metrics.setToDefaults();

        final Configuration config = new Configuration();
        config.setToDefaults();

        mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
                new DisplayAdjustments());
    }
找到了,在这里,这里new了一个实例,并调用了setToDefaults()方法,那我们看看DisplayMetrics类的构造方法和setToDefaults()方法里有没有对类里面的变量赋值的操作吧
public DisplayMetrics() {
    }
public void setToDefaults() {
        widthPixels = 0;
        heightPixels = 0;
        density =  DENSITY_DEVICE / (float) DENSITY_DEFAULT;         //看这行
        densityDpi =  DENSITY_DEVICE;
        scaledDensity = density;                                    //看这行
        xdpi = DENSITY_DEVICE;                                      //看这行
        ydpi = DENSITY_DEVICE;
        noncompatWidthPixels = widthPixels;
        noncompatHeightPixels = heightPixels;
        noncompatDensity = density;
        noncompatDensityDpi = densityDpi;
        noncompatScaledDensity = scaledDensity;
        noncompatXdpi = xdpi;
        noncompatYdpi = ydpi;
    }
哇,看到了,是在setToDefaults()方法方法里进行了赋值操作

我们可以看到我们需要的density、scaledDensity、xdpi和DENSITY_DEVICE 、DENSITY_DEFAULT有关系

 

DENSITY_DEVICE、DENSITY_DEFAULT是什么

    /**
     * The device's current density.
     * <p>
     * This value reflects any changes made to the device density. To obtain
     * the device's stable density, use {@link #DENSITY_DEVICE_STABLE}.
     *
     * @hide This value should not be used.
     * @deprecated Use {@link #DENSITY_DEVICE_STABLE} to obtain the stable
     *             device density or {@link #densityDpi} to obtain the current
     *             density for a specific display.
     */
    @Deprecated
    public static int DENSITY_DEVICE = getDeviceDensity();
private static int getDeviceDensity() {
        // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
        // when running in the emulator, allowing for dynamic configurations.
        // The reason for this is that ro.sf.lcd_density is write-once and is
        // set by the init process when it parses build.prop before anything else.
        return SystemProperties.getInt("qemu.sf.lcd_density",
                SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
    }

DENSITY_DEVICE是当前设配的密度,该值由getDeviceDensity()方法读取手机上的配置文件得来

 

 

public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;

而DENSITY_MEDIUM则是

public static final int DENSITY_MEDIUM = 160;

看到这里我想你应该知道了,为什么160dpi下的density=1了(此处应有表情包,可惜太麻烦了,懒得扔上来鄙视

好吧,到这里就结束了

哎,你还没说怎么变换?上面不是有公式么,自己换算去

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值