很久以前就想写一篇跟屏幕适配相关的文章一直没有动笔,此次下决心抽周末的时间结合我在实际项目中所遇到的问题写一篇博客。html
Android手机屏幕是由不少的像素点(pixels)组成的,从左到右称为x轴,从上到下为y轴。屏幕的分辨率就是屏幕上x轴上的像素点格式乘以y轴上的像素点个数。320*480的屏幕就是有320个像素点在x轴上,有480个像素点在y轴上。以下图所示:java
什么是屏幕的大小? 对于手机,平板,电脑,或者电视,一般用屏幕的对角线的长度单位为英尺(inches,1 英尺=2.54厘米)来表示屏幕的大小。 若是知道屏幕的宽度和高度就能够计算出屏幕的大小。以下图所示: android
屏幕密度指的是单位面积上的像素点的个数。像素点(pixel)屏幕上最小的显示区域,不一样分辨率的手机上像素点的大小不同,一样尺寸的屏幕像素点越大屏幕上的像素点总数越少,分辨率越低,像素点越小,屏幕上像素点个数越多,分辨率越高。以下图所示: bash
DPI(Dots Per Inch),每一英尺上像素点的个数,dpi是用于衡量屏幕分辨率的尺度,dpi越大屏幕分辨率越高,DPI计算公式:app
240x320, 1.5"x2"
复制代码
上面是一个240320也就是说x轴像素点240pixels,y轴像素点320pixels,屏幕尺寸1.52,物理尺寸长2英尺,宽1.5英尺。 先计算屏幕的大小 ide
240x320, 1.5"x2"
复制代码
的dpi是160.wordpress
一、像素(px)布局
含义:一般所说的像素,就是CCD/CMOS上光电感应元件的数量,一个感光元件通过感光,光电信号转换,A/D转换等步骤之后,在输出的照片上就造成一个点,咱们若是把影像放大数倍,会发现这些连续色调实际上是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。简而言之,像素就是手机屏幕的最小构成单元。 单位:px(pixel),1px = 1像素点 通常状况下UI设计师的设计图会以px做为统一的计量单位。字体
二、分辨率ui
含义:手机在横向、纵向上的像素点数总和 通常描述成 宽*高 ,即横向像素点个数 * 纵向像素点个数(如1080 x 1920)。 单位:px(pixel),1px = 1像素点
三、屏幕尺寸(in)
含义:手机对角线的物理尺寸 单位 英寸(inch),一英寸大约2.54cm 常见的尺寸有4.7寸、5寸、5.5寸、6寸
四、屏幕像素密度(dpi)
含义:每英寸的像素点数。 例如每英寸内有160个像素点,则其像素密度为160dpi。 单位:dpi(dots per inch) 计算公式: 像素密度 = 像素 / 尺寸 (dpi = px / in) 标准屏幕像素密度(mdpi): 每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)。
dp与px的换算方法
px=density*dp
所以dp与px的换算方法以下:
px = dp * (dpi / 160)
复制代码
分辨率和屏幕密度以及像素大小之间的关系以下图:
若是在布局中直接使用px来作单位会有什么问题,以下图,在图中a的宽度为2px,高度为2px,在左图中因为像素点比右图像素点大,所以做图中的a明显比右图中的a大。
下面来看下在Android中为何要在不一样的分辨率的目录下放大小不一样的图:好比在drawable,drawable-hdpi,drawable-xhdpi,drawable-xxhdpi,drawable-xxxhdpi目录下图片大小不同:
注意在Android中全部的尺寸单位最后都是转化为px后再显示的,由于屏幕显示的基本单位就是px
private float dipToPx(float dip) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
getResources().getDisplayMetrics());
}
复制代码
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和dp的转换与metrics.density
相关,下面看一下源码里面对metrics.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 */
复制代码
上面的总结一下就是:标准状况下240x320, 1.5"x2"
的屏幕上density=1,就是说物理尺寸时1.52英寸的状况下,可是当240320屏幕物理尺寸不是1.52的时候此时density仍是等于1。由dpi和density的计算公式可知这时的density是有问题的。由于此时240320因为物理尺寸不是1.5*2,算出来的dpi不等于160。
public static final int DENSITY_DEFAULT = 160;
density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
复制代码
若是density计算有问题那么dp转换为px就会有问题,因此在有些手机上有时就会出现很奇怪的适配问题,好比字体显示偏小,布局偏小等等,解决这个问题可使用下面方法:即提供一个计算density的方法不用系统的density计算致使的问题。
public class ScreenUtils {
//Negotiate with the designer to define a design dimension. Here is 1920*1080 resolution set.
private static final float widthdp = 360f;
private static final float heightdp = 640f;
//Recording system settings
private static float systemDensity = 0;
private static float systemScaledDensity = 0;
public void setCustomDensity(@NonNull final Activity activity) {
DisplayMetrics displayMetrics = activity.getApplication().getResources().getDisplayMetrics();
if (systemDensity == 0) {
//Initialization
systemDensity = displayMetrics.density;
systemScaledDensity = displayMetrics.scaledDensity;
//Add a listener. If the user changes the font of the system, the system will return the listener.
activity.getApplication().registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
systemScaledDensity = activity.getApplication().getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
//Target value calculation => PX = DP * density
final float targetDensity = displayMetrics.widthPixels / widthdp;
final float targetScaledDensity = targetDensity * (systemScaledDensity / systemDensity);
final int targetDensityDpi = (int) (160 * targetDensity);
//Set the calculated value
displayMetrics.density=targetDensity;
displayMetrics.scaledDensity=targetScaledDensity;
displayMetrics.densityDpi=targetDensityDpi;
//Set the value of activity
final DisplayMetrics activityDisplayMetrics =activity .getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
}
}
复制代码
一、 stackoverflow.com/questions/2…
二、 developer.android.com/guide/pract…
三、 developer.android.com/training/mu…
四、 developer.android.com/guide/pract…
五、 laaptu.wordpress.com/tag/android…
六、 www.codexiu.cn/android/blo…