比起IOS開發總共不過區區幾種設備型號,作爲Android開發者,面對成千上萬的機型,屏幕適配的工作就顯得尤爲重要。
官方中關於屏幕適配的幾點建議:
- 拉伸和壓縮你的佈局,以適應各種不同的高度和寬度。
- 在更大的設備上,可以利用額外的屏幕。結合多個視圖 創建複合控件來顯示更多內容和輕鬆導航。
- 爲不同的屏幕密度(DPI)設備提供多套資源,以確保應用程序在任何設備上看起來不錯。
1.px , dp,sp的定義
px(pixels)像素,意思是屏幕上的點。在設計領域中,像素是用來計算數碼影像的最小單位。如 800*400。
dpi 是Dots Per Inch的縮寫, 每英寸點數,即每英寸包含像素個數。比如320X480分辨率的手機,寬2英寸,高3英寸, 每英寸包含的像素點的數量爲320/2=160dpi(橫向)或480/3=160dpi(縱向),160就是這部手機的dpi,橫向和縱向的這個值都是相同的,原因是大部分手機屏幕使用正方形的像素點。手機dpi越大也就是俗稱分辨率也高。
dp 也即dip,設備獨立像素,device independent pixels的縮寫,Android特有的單位,在屏幕密度dpi = 160屏幕上,1dp = 1px。android爲了支持LDPI (120dpi), MDPI (160dpi), HDPI(240dpi), XHDPI (320dpi), and XXHDPI(480dpi) 使用這個,而不依賴像素單位。在定義佈局width/height值,推薦使用dp作單位。 dx和dp的換算:dx=dp*density
sp scaled pixels(比例放大像素). 主要用於字體顯示best for textsize,sp是爲了保證相同字號的字在不同PPI屏幕上顯示的物理高度一致。
2.單位的換算,設備屏幕信息
1)、獲取設備的屏幕信息
/**
* 獲取設備的屏幕信息
*
* @return
*/
public static void getWindowInfo(Context context) {
// DisplayMetrics類用於屏幕的描述信息
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
// 獲取屏幕密度,在dpi=160的設備上density=1; density=dpi/160
float density = displayMetrics.density;
// 獲取屏幕dpi,即每英寸包含像素個數
int dpi = displayMetrics.densityDpi;
// 獲取屏幕像素寬度 px
int width = displayMetrics.widthPixels;
// 獲取屏幕像素高度 px
int height = displayMetrics.heightPixels;
Log.i(TAG, "屏幕密度:" + density + "\t dpi=" + dpi + "\t width=" + width
+ "\t height=" + height);
}
2)、單位的換算,px和dp的相互換算
/**
* 把px 轉化爲dip
*
* @param context
* @param px
* @return
*/
public static int px2dip(Context context, float px) {
float density = context.getResources().getDisplayMetrics().density;// 密度
int dip = (int) (px / density + 0.5f);
return dip;
}
/**
* 把dip轉化爲px
*
* @param context
* @param dp
* @return
*/
public static float dip2px(Context context, float dp) {
float density = context.getResources().getDisplayMetrics().density;// 密度
float px = dp * density;
return px;
}
3)、屏幕座標的獲取
Android的屏幕座標是從 左上角(0,0)起始,右下角結束。以1280*720手機爲例,屏幕座標如下圖,單位爲PX
view.getLocationOnScreen(pos); // 獲取在當前窗口內的絕對座標
view.getLocationInWindow(pos); // 得到view在整個屏幕內上的位置
注意:該方法在oncreate中執行返回值爲(0,0),因爲該控件還未在activity中生成,建議在 onWindowFocusChanged(boolean hasFocus) 方法中調用
/**
* 獲取指定控件的座標[只能再oncreate之後的生命週期中執行,否則返回(0,0)]
*
* @param view
* 指定控件
* @return 長度爲2的int數組pos,X=pos[0] ,Y=pos[1]
*/
public static int[] getPosition(View view) {
int pos[] = new int[2];
// 獲取在當前窗口內的絕對座標
// view.getLocationOnScreen(pos);
// 得到view在整個屏幕內上的位置
view.getLocationInWindow(pos);
Log.i(TAG, pos[0] + "---" + pos[1]);
return pos;
}
4)、獲取Android手機頂部狀態欄高度,底部虛擬鍵盤位置的獲取
實際開發中會遇到獲取頂部狀態欄的高度的情況,如設置全屏PopupWindow需要設置 popupWindow的高度= 屏幕高度- 狀態欄高度
虛擬按鍵的情況,針對一些特殊型號的手機,如魅族系列等在屏幕底部時手機的虛擬按鍵,此時就有必要針對此類型號手機計算虛擬按鍵的位置或高度,全屏PopupWindow需要設置popupWindow的高度= 屏幕高度- 狀態欄高度-底部虛擬鍵盤高度。
public static int getStatusBarHeight(Activity activity) {
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top; // 狀態欄高度
int bottomHeight = rect.bottom;// 底部虛擬鍵盤的
Log.i(TAG, "statusBarHeight=" + statusBarHeight + "---bottomHeight="
+ bottomHeight);
return statusBarHeight;
}
如果該方法獲取值0,解決辦法可以參看我的另外一篇文章獲取android頂部狀態欄高度的兩種方式