1、宽高限定符适配
1.1 原理:
就是穷举市面上所有的Android手机的宽高像素值,设定一个基准的分辨率,其他分辨率都根据这个基准分辨率来计算,在不同的尺寸文件夹内部,根据该尺寸编写对应的dimens文件
1.2 缺点:
这个方案有一个致命的缺陷,那就是需要精准命中才能适配,比如1920x1080的手机就一定要找到1920x1080的限定符,否则就只能用统一的默认的dimens文件了。而使用默认的尺寸的话,UI就很可能变形,简单说,就是容错机制很差。
1.3 集成
1.3.1 dimens文件生成工具
autolayout.jar
在你下载后的文件夹里面 按住Shift+鼠标右击进入命令行对话框,输入java -jar autolayout.jar 720 1280就会自动生成res文件夹(默认的是以1080/1280为基准,所以需要自己设置),假如你觉得这些value文件夹里面没有你想要的分辨率可以在制定基准分辨率的同时,添加额外的分辨率(比如400/600),输入java -jar autolayout.jar 720 1280 400,600,假如想多添加几个额外的分辨率(又想添加500*700)只需把额外的分辨率用下划线隔开即可,输入java -jar autolayout.jar 720 1280 400,600_500,700
1.3.2 生成示例如下图
将生成的文件复制到自己工程的res下就可以了
2、SmallestWidth适配(sw限定符适配)
2.1 实现原理:
Android会识别屏幕可用高度和宽度的最小尺寸的dp值,然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。
sw限定符适配 和 宽高限定符适配类似,区别在于,前者有很好的容错机制,如果没有value-sw360dp文件夹,系统会向下寻找,比如离360dp最近的只有value-sw350dp,那么Android就会选择value-sw350dp文件夹下面的资源文件。这个特性就完美的解决了上文提到的宽高限定符的容错问题。
2.2 优点:
非常稳定,极低概率出现意外
不会有任何性能的损耗
适配范围可自由控制,不会影响其他三方库
2.3 缺点:
在布局中引用 dimens 的方式,虽然学习成本低,但是在日常维护修改时较麻烦
侵入性高,如果项目想切换为其他屏幕适配方案,因为每个 Layout 文件中都存在有大量 dimens 的引用,这时修改起来工作量非常巨大,切换成本非常高昂
无法覆盖全部机型,想覆盖更多机型的做法就是生成更多的资源文件,但这样会增加 App 体积,在没有覆盖的机型上还会出现一定的误差,所以有时需要在适配效果和占用空间上做一些抉择
如果想使用 sp,也需要生成一系列的 dimens,导致再次增加 App 的体积
不能自动支持横竖屏切换时的适配,如上文所说,如果想自动支持横竖屏切换时的适配,需要使用 values-wdp 或 屏幕方向限定符 再生成一套资源文件,这样又会再次增加 App 的体积
2.4 集成
2.4.1生成工具地址
2.4.2 生成示例如下图
3、今日头条适配(AutoSize)
3.1 实现原理:
原文章地址
而今日头条屏幕适配方案的核心原理在于修改 density。采用的是dp适配
下面假设设计图宽度是360dp,以宽维度来适配。
那么适配后的 density = 设备真实宽(单位px) / 360,接下来只需要把我们计算好的 density 在系统中修改下即可,代码实现如下:
3.2 下面是今日头条给出的案例代码:
// 系统的Density
private static float sNoncompatDensity;
// 系统的ScaledDensity
private static float sNoncompatScaledDensity;
public static void setCustomDensity(Activity activity, Application application) {
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
if (sNoncompatDensity == 0) {
sNoncompatDensity = displayMetrics.density;
sNoncompatScaledDensity = displayMetrics.scaledDensity;
// 监听在系统设置中切换字体
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
sNoncompatScaledDensity=application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
// 此处以360dp的设计图作为例子
float targetDensity=displayMetrics.widthPixels/360;
float targetScaledDensity=targetDensity*(sNoncompatScaledDensity/sNoncompatDensity);
int targetDensityDpi= (int) (160 * targetDensity);
displayMetrics.density = targetDensity;
displayMetrics.scaledDensity = targetScaledDensity;
displayMetrics.densityDpi = targetDensityDpi;
DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
3.3 优点:
使用成本非常低,操作非常简单,使用该方案后在页面布局时不需要额外的代码和操作
侵入性非常低,该方案和项目完全解耦,在项目布局时不会依赖哪怕一行该方案的代码,而且使用的还是 Android 官方的 API,意味着当你遇到什么问题无法解决,想切换为其他屏幕适配方案时,基本不需要更改之前的代码,整个切换过程几乎在瞬间完成,会少很多麻烦,节约很多时间,试错成本接近于 0
可适配三方库的控件和系统的控件(不止是是 Activity 和 Fragment,Dialog、Toast 等所有系统控件都可以适配),由于修改的 density 在整个项目中是全局的,所以只要一次修改,项目中的所有地方都会受益
不会有任何性能的损耗
3.4 缺点:
只需要修改一次 density,项目中的所有地方都会自动适配,这个看似解放了双手,减少了很多操作,但是实际上反应了一个缺点,那就是只能一刀切的将整个项目进行适配,但适配范围是不可控的
3.5 集成 使用AndroidAutoSize
3.5.1 简介
AndroidAutoSize 是基于今日头条适配方案,该开源库已经很大程度上解决了今日头条适配方案的两个缺点,可以对activity,fragment进行取消适配。也是目前我的项目中所使用的适配方案。
使用也非常简单只需两步:
引入:
implementation 'me.jessyan:autosize:1.1.2'
在 AndroidManifest 中填写全局设计图尺寸 (单位 dp),如果使用副单位,则可以直接填写像素尺寸,不需要再将像素转化为 dp
<manifest>
<application>
<meta-data
android:name="design_width_in_dp"
android:value="360"/>
<meta-data
android:name="design_height_in_dp"
android:value="640"/>
</application>
</manifest>