android系統中DP和SP的轉化:
1.首先分析TypedValue.java
可以調用以下代碼獲得dp的值
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20,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; }
2.接着分析Resource.java
在Resoucrce中會調用 mMetrics.setToDefaults();設置DisplayMetrics的density的值
1 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config, 2 CompatibilityInfo compatInfo, IBinder token) { 3 mAssets = assets; 4 mMetrics.setToDefaults(); 5 if (compatInfo != null) { 6 mCompatibilityInfo = compatInfo; 7 } 8 mToken = new WeakReference<IBinder>(token); 9 updateConfiguration(config, metrics); 10 assets.ensureStringBlocks(); 11 } 12 13 public void setToDefaults() { 14 widthPixels = 0; 15 heightPixels = 0; 16 density = DENSITY_DEVICE / (float) DENSITY_DEFAULT; 17 densityDpi = DENSITY_DEVICE; 18 scaledDensity = density; 19 xdpi = DENSITY_DEVICE; 20 ydpi = DENSITY_DEVICE; 21 noncompatWidthPixels = widthPixels; 22 noncompatHeightPixels = heightPixels; 23 noncompatDensity = density; 24 noncompatDensityDpi = densityDpi; 25 noncompatScaledDensity = scaledDensity; 26 noncompatXdpi = xdpi; 27 noncompatYdpi = ydpi; 28 } 29 30 DENSITY_DEFAULT默認值為160,在系統中可以更改這個值 31 public static int DENSITY_DEVICE = getDeviceDensity(); 32 33 private static int getDeviceDensity() { 34 35 return SystemProperties.getInt("qemu.sf.lcd_density", 36 SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT)); 37 } 38 39 40 41 DENSITY_DEVICE是通過計算屏幕分辨率得出的,計算方式如下:
ro.sf.lcd_density的屬性值:
-------------------------------
對於分辨路為720*1280 5.5寸:
ro.sf.lcd_density = 320
320/160 = 2
計算方式:720*1280 5.5寸 1280*1280+720*720 = 1648.6047/5.5 = 267.0190(取320)
--------------------------------------------------------------------
對於分辨路為1080*1920 5.5寸::
ro.sf.lcd_density = 320
480/160 = 3:
計算方式:1080*1920 5.5寸 2202.90707/5.5 = 400.5285(取480)
系統會將計算出的DPI轉化成(120 160 240 320 480)
4.
通過以上分析可知
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20,
getResources().getDisplayMetrics());
=20*getProp("ro.sf.lcd_density")/DENSITY_DEFAULT
= 20*getProp("ro.sf.lcd_density")/160
5在實際編程中,我們常用的dp和px轉化代碼是:區別就在於將float轉化成了int,僅此而已
/** * 根據手機的分辨率從 dp 的單位 轉成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根據手機的分辨率從 px(像素) 的單位 轉成為 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); }