很久以前就想寫一篇跟屏幕適配相關的文章一直沒有動筆,此次下決心抽週末的時間結合我在實際項目中所遇到的問題寫一篇博客。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…