最近在看了許多關於dp-px,px-dp,sp-px,px-sp之間轉化的博文,過去我比較常用的方式是:
1 //轉換dip為px 2 public static int convertDipOrPx(Context context, int dip) { 3 float scale = context.getResources().getDisplayMetrics().density; 4 return (int)(dip*scale + 0.5f*(dip>=0?1:-1)); 5 } 6 7 //轉換px為dip 8 public static int convertPxOrDip(Context context, int px) { 9 float scale = context.getResources().getDisplayMetrics().density; 10 return (int)(px/scale + 0.5f*(px>=0?1:-1)); 11 }
然后看到了一種新的轉化方式,代碼如下:
1 public static int dp2sp(float dpVal){ 2 return (int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, 3 MyAppliction.getInstance().getApplicationContext().getResources().getDisplayMetrics())); 4 } 5 //????? 6 public static int sp2dp(float spVal){ 7 return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, 8 MyAppliction.getInstance().getApplicationContext().getResources().getDisplayMetrics())); 9 }
碼農對TypedValue充滿好奇,通過查詢官網了解該類
TypedValue
---android.util.TypedValue
Container for a dynamically typed data value. Primarily used with Resources
for holding resource values.
翻譯過來就是:這個類是工具類,作為一個動態容器,它存放一些數據值,這些值主要是resource中的值。
我們來理解一下:resource中到底有哪些值?layout、drawable、string、style、anim、dimens、menu、colors、ids這些值一些和屏幕適配有直接的關系。
有一些方法必然是可以讀取這些資源文件信息的,比如:
getDimension(DisplayMetrics metrics)
再看具體的方法:
applyDimension(int unit, float value,DisplayMetrics metrics)
第一個參數是單位,第二個參數是對應值,第三個你懂的,封裝了顯示區域的各種屬性值。
對於applyDimension(int unit, float value,DisplayMetrics metrics)中的代碼我們來看下
1 public static float applyDimension(int unit, float value, 2 DisplayMetrics metrics) 3 { 4 switch (unit) { 5 case COMPLEX_UNIT_PX: 6 return value; 7 case COMPLEX_UNIT_DIP: 8 return value * metrics.density; 9 case COMPLEX_UNIT_SP: 10 return value * metrics.scaledDensity; 11 case COMPLEX_UNIT_PT: 12 return value * metrics.xdpi * (1.0f/72); 13 case COMPLEX_UNIT_IN: 14 return value * metrics.xdpi; 15 case COMPLEX_UNIT_MM: 16 return value * metrics.xdpi * (1.0f/25.4f); 17 } 18 return 0; 19 }
其中單位為dip的,將其轉化為密度*值,也就是像素值,而單位sp的也將其轉化為px值,因此該方法可以能進行
dip-->px
sp-- >px
因此上面
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, value ,DisplayMetrics );
這個方法肯定不能將sp轉化為dp,我們判斷
dp2sp(50) = 150
sp2dp(50) = 150
convertDipOrPx(50) = 150
convertPxOrDip(50) = 17
將代碼運行實際結果與判斷結果一致。
接下來我們繼續分析
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, value ,DisplayMetrics );
該方法系統本意是用來做什么的?
查看官方說明:
Converts an unpacked complex data value holding a dimension to its final floating point value.
這里就把對應的值轉化為實際屏幕上的點值,也就是像素值。
如果是TypedValue.COMPLEX_UNIT_DIP,則乘以顯示密度density。
而如果是TypedValue.COMPLEX_UNIT_SP,則乘以像素密度scaledDensity。
我們繼續刨根追底
density和scaledDensity的區別在於
density:The logical density of the display.顯示密度density = dpi/160
scaledDensity:A scaling factor for fonts displayed on the display.顯示字體的縮放因子 = density
實際上兩者的值一樣,為了驗證這個結論我們隨便找兩台機器小米2S和華為p7,取出density和scaledDensity是一致的,P7為3.0,小米2S = 2.0
因此本文結論轉化dp-px,px-dp,sp-px,px-sp
使用下面方法:
1 //轉換dip為px 2 public static int convertDipOrPx(Context context, int dip) { 3 float scale = context.getResources().getDisplayMetrics().density; 4 return (int)(dip*scale + 0.5f*(dip>=0?1:-1)); 5 } 6 7 //轉換px為dip 8 public static int convertPxOrDip(Context context, int px) { 9 float scale = context.getResources().getDisplayMetrics().density; 10 return (int)(px/scale + 0.5f*(px>=0?1:-1)); 11 } 12 13 public static int sp2px(Context context, float spValue) { 14 float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 15 return (int) (spValue * fontScale + 0.5f); 16 } 17 18 public static int px2sp(Context context, float pxValue) { 19 float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 20 return (int) (pxValue / fontScale + 0.5f); 21 }
如有錯誤,敬請指正。