android适配,是android中非常重要的内容,我们平时做适配时,一般会相对布局、wrap_content、线性比例、单位dp等来做,仅仅做这些其实仅仅算及格,并不能完美适配,比如某个按钮宽高,如果仅仅是写一个dp,那么多数手机可能匹配,但仍然会有部分机型是不能满足要求的,那么我们该如何来做呢?我们先了解一下屏幕适配的基础知识,然后再详情适配方案
基础知识
- 像素
- 含义:通常所说的像素,就是CCD/CMOS上光电感应元件的数量,一个感光元件经过感光,光电信号转换,A/D转换等步骤以后,在输出的照片上就形成一个点,我们如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。简而言之,像素就是手机屏幕的最小构成单位。
- 单位:px(pixel),1px = 1像素点
- 一般情况下UI设计师的设计图会以px作为统一的计量单位
- 分辨率
- 含义:手机在横向、纵向上的像素点数总和
- 一般描述成 宽*高,即横向像素点个数 * 纵向像素点个数(如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)
- 标准屏幕像素密度(mdi):每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)
- 密度无关像素(dp)
- 含义:density-independent pixel,叫dp或者dip,与终端的实际物理像素点无关
- 单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果,是安卓特有的长度单位
- 屏幕宽度是320dp
- dp与px的转换: px = dp * (dpi/160)
- 独立比例像素(sp)
- 含义:scale-independent pixel,叫sp或sip
- 单位:sp,字体大小专用单位
- Android开发时用此单位设置文字大小,可根据字体大小首选项进行缩放
- 推荐使用12sp、14sp、18sp、22sp作为字体大小,不推荐使用奇数和小数,容易造成精度丢失,12sp以下字体太小
- sp与dp的区别
- dp只跟屏幕的像素密度有关
- sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小,文字尺寸设置为标准时,1sp=1dp,当文字尺寸设置为特大号时,1sp>1dp
- 屏幕分辨率对应表
密度类型 | 分辨率 | 屏幕像素密度 | density | 换算 |
---|---|---|---|---|
低密度(ldpi) | 240X320 | 0-120 | 0.75 | 1dp=0.75px |
中密度(mdpi) | 320X480 | 120-160 | 1 | 1dp=1px |
高密度(hdpi) | 480X800 | 160-240 | 1.5 | 1dp=1.5px |
超高密度(xhdpi) | 720X1280 | 240-320 | 2 | 1dp=2px |
超超高密度 | 1080X1920 | 320-480 | 3 | 1dp=3px |
- 屏幕尺寸、分辨率、像素密度关系
适配优化
dp单位优化
- 根据实际的宽高重新计算density并应用,我们使用dp时有时候会不对的原因是各大厂商对宽高的定制没有完全满足google的规则,导致density不正确,而 px = dp*density,从而引起实际像素计算不正确,所以根据屏幕实际的宽高重新计算density并应用,代码如下
//三种获取DisplayMetrics的方式
final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
//第二种方式
//DisplayMetrics metrics = new DisplayMetrics();
//Display display = getWindowManager().getDefaultDisplay();
//display.getMetrics(metrics);
//第三种方式
// DisplayMetrics metrics2 = Resources.getSystem().getDisplayMetrics();
if(sNoncompatDensity == 0){
// 系统的Density
sNoncompatDensity = appDisplayMetrics.density;
// 系统的ScaledDensity
sNoncompatScaleDensity = appDisplayMetrics.scaledDensity;
// 监听在系统设置中切换字体
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
if(newConfig != null && newConfig.fontScale > 0){
sNoncompatScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
final float targetDensity = appDisplayMetrics.widthPixels / 480;
final float targetScaledDensity = targetDensity * (sNoncompatScaleDensity/sNoncompatDensity);
final int targetDensityDpi = (int)(160 * targetDensity);
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.scaledDensity = targetScaledDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
- 自动生成 x1、x2 与像素的对应关系,实际使用时单位使用 x1、x2即可,设计图按照320*480来设计,这时候1px就等于x1,即可完成所有屏幕的适配,代码github地址
布局组件的适配
- 使用密度无关像素指定尺寸
- 使用相对布局或线性布局,不要使用绝对布局
- 使用wrap_content、match_parent、权重
- 使用minWidth、minHeight、lines等属性
- dimens使用
布局的适配
- 使用Size限定符
- 最小宽度限定符
- 使用布局别名
- 使用屏幕方向限定符
- 多套layout适配
- 以上适配的官方google说明
图片适配
- 普通图片和图标
- 自动拉伸位图:Nine-Patch的图片类型
- 动画、自定义View、shape
- logo图标
屏幕密度 | 对应的图片大小(px) | 图片资源目录 |
---|---|---|
120dip | 36*36 | mipmap-ldpi |
160dip | 48*48 | mipmap或者mipmap-mdpi |
240dip | 72*72 | mipmap-hdpi |
320dip | 96*96 | mipmap-xhdpi |
480dip | 114*114 | mipmap-xxhdpi |
640dip | 192*192 | mipmap-xxxhdpi |
- ImageView的ScaleType适配
android:scaleType=“center” 保持原图的大小,显示在ImageView的中心。当原图的size大于ImageView的size时,多出来的部分被截掉
android:scaleType=“center_inside”以原图正常显示为目的,如果原图大小大于ImageView的size,就按照比例缩小原图的宽高,居中显示在ImageView中。如果原图size小于ImageView的size,则不做处理居中显示图片
android:scaleType=center_crop 以原图填满ImageView为目的,如果原图size大于ImageView的size,则与center_inside一样,按比例缩小,居中显示在ImageView上。如果原图size小于ImageView的size,则按比例拉升原图的宽和高,填充ImageView居中显示
android:scaleType=“matrix” 不改变原图的大小,从ImageView的左上角开始绘制,超出部分做剪切处理
androd:scaleType=“fit_xy” 把图片按照指定的大小在ImageView中显示,拉伸显示图片,不保持原比
刘海屏适配
折叠屏适配
版本适配
- Android 6.X,新增运行时权限,可使用RxPermissions
- Android 7.X,进程共享文件时,需使用FileProvider,用法请点击