比起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顶部状态栏高度的两种方式
.9.png图片的使用与制作