原文地址: https://www.jianshu.com/p/4aa...java
如下是 骚年你的屏幕适配方式该升级了! 系列文章,欢迎转发以及分享:android
我在前面两篇文章中详细介绍了 今日头条适配方案 和 SmallestWidth 限定符适配方案 的原理,并验证了它们的可行性,以及总结了它们各自的优缺点,能够说这两个方案都是目前比较优秀、比较主流的 Android 屏幕适配方案,并且它们都已经拥有了必定的用户基数git
可是对于一些才接触这两个方案的朋友,确定或多或少仍是不知道如何选择这两个方案,我虽然在以前的文章中给出了它们各自的优缺点,可是并无用统一的标准对它们进行更细致的对比,因此也就没办法更形象的体现它们的优劣,那下面我就用统一的标准对它们进行对比,看看它们的对比状况github
我始终坚决地认为在这两个方案中,并不能以单个标准就能评判出谁必定比谁好,由于它们都有各自的优缺点,都不是完美的,从更客观的角度来看,它们谁都不能成为最好的那个,只有可能明确了它们各自的优缺点,知道在它们的优缺点里什么是我能接受的,什么是我不能接受的,是否能为了某些优势作出某些妥协,从而选择出一个最适合本身项目的屏幕适配方案面试
单纯的争论谁是最好的 Android 屏幕适配方案没有任何意义,每一个人的需求不同,站的角度不同,评判标准也不同,你能接受的东西他不必定能接受,你以为不可接受的东西他却以为能够接受,你有你的理由,他有他的理由,想让一个观点让全部人都能接受太难了!因此我在这里只是列出它们的对比项和对比结果,尽量的作到客观,最后的选择结果请自行决定,若是还有什么遗漏的对比项,请补充!安全
对比项目 | 对比对象 A | 对比结果 | 对比对象 B |
---|---|---|---|
适配效果(越高越好) | 今日头条适配方案 | ≈ | SW 限定符适配方案(在未覆盖的机型上会存在必定的偏差) |
稳定性(越高越好) | 今日头条适配方案 | < | SW 限定符适配方案 |
灵活性(越高越好) | 今日头条适配方案 | > | SW 限定符适配方案 |
扩展性(越高越好) | 今日头条适配方案 | > | SW 限定符适配方案 |
侵入性(越低越好) | 今日头条适配方案 | < | SW 限定符适配方案 |
使用成本(越低越好) | 今日头条适配方案 | < | SW 限定符适配方案 |
维护成本(越低越好) | 今日头条适配方案 | < | SW 限定符适配方案 |
性能损耗 | 今日头条适配方案没有性能损耗 | = | SW 限定符适配方案没有性能损耗 |
反作用 | 今日头条适配方案会影响一些三方库和系统控件 | ≈ | SW 限定符适配方案会影响 App 的体积 |
能够看到 SmallestWidth 限定符适配方案 和 今日头条适配方案 的适配效果其实都是差很少的,我在前面的文章中也经过公式计算过它们的精确度,SmallestWidth 限定符适配方案 运行在未覆盖的机型上虽然也能够适配,可是却会出现必定的偏差,因此 今日头条适配方案 的适配精确度确实要比 SmallestWidth 限定符适配方案 略高的,不过只要 SmallestWidth 限定符适配方案 合理的分配资源文件,适配效果的差距应该也不大架构
SmallestWidth 限定符适配方案 主打的是稳定性,在运行过程当中极少会出现安全隐患,适配范围也可控,不会产生其余未知的影响,而 今日头条适配方案 主打的是下降开发成本、提升开发效率,使用上更灵活,也能知足更多的扩展需求,简单一句话归纳就是,这两兄弟,一个求稳,一个求快,好了,我就介绍这么多了,本身选择吧!app
下面就开始介绍我根据 今日头条屏幕适配方案 优化的屏幕适配框架 AndroidAutoSize,你们千万不要认为,我推出的屏幕适配框架 AndroidAutoSize 是根据 今日头条屏幕适配方案 优化的,我本人就必定支持 今日头条屏幕适配方案 是最好的 Android 屏幕适配方案这个观点,它确实很优秀,但一样也有不少不足,我最真实的观点在上面就已经表述咯,至于我为何要根据 今日头条屏幕适配方案 再封装一个屏幕适配框架,无外乎就如下几点缘由:框架
我建议你们均可以去实际体验一下 今日头条屏幕适配方案 和 SmallestWidth 限定符适配方案,感觉下它们的异同,我给的建议是,能够在项目中先使用 今日头条屏幕适配方案,感觉下它的使用方式以及适配效果,今日头条屏幕适配方案 的侵入性很是低,若是在使用过程当中遇到什么不能解决的问题,立刻能够切换为其余的屏幕适配方案,在切换的过程当中也花费不了多少工做量,试错成本很是低ide
但若是你在项目中先使用 SmallestWidth 限定符适配方案,以后在使用的过程当中再遇到什么不能解决的问题,这时想切换为其余的屏幕适配方案,这工做量可就大了,每一个 Layout 文件都含有大量的 dimens 引用,改起来这工做量得有多大,想一想都以为后怕,这就是侵入性过高致使的最致命的问题
若是想体验 今日头条屏幕适配方案,千万不要错过 AndroidAutoSize 哦!仅需一步便可接入项目,下面是 AndroidAutoSize 的地址:
Github : 您的 Star 是我坚持的动力 ✊
AndroidAutoSize 与 今日头条屏幕适配方案 的关系,至关于汽车和发动机的关系,今日头条屏幕适配方案 官方公布的代码,只实现了修改系统 density 的相关逻辑,这的确在屏幕适配中起到了最关键的做用,但这还远远还不够
要想让使用者可以更傻瓜式的使用该方案,而且可以应对平常开发中的全部复杂需求,那在架构框架时,还须要考虑 API 的易用性以及合理性、框架的扩展性以及灵活性、功能的全面性、注释和文档的易读性等多个方面的问题
因而我带着个人这些标准在网上搜寻了好久,发现并无任何一个开源框架或解决方案可以达到个人全部标准,它们大多数还只是停留在将 今日头条屏幕适配方案 封装成工具类来引入项目的阶段,这样在功能的扩展上有限制,而且对用户的使用体验也很差,而我想作的是一个全面性的产品级屏幕适配框架,这离我最初的构想,差距还很是大,因而我只好本身动手,将个人全部思想实现,这才有了 AndroidAutoSize
写完 AndroidAutoSize 框架后,由于对 今日头条屏幕适配方案 有了更加深刻的理解,因此才写了 骚年你的屏幕适配方式该升级了!(一)-今日头条适配方案,以帮助你们更清晰的理解 今日头条屏幕适配方案
AndroidAutoSize 由于名字和 鸿神 的 AndroidAutoLayout 很是类似,而且在填写设计图尺寸的方式上也极为类似,再加上我写的屏幕适配系列的文章也发布在了 鸿神 的公众号上,因此不少人觉得 AndroidAutoSize 是 鸿神 写的 AndroidAutoLayout 的升级版,这里我啼笑皆非 😂,我只好在这里说一句,你们好,我叫 JessYan,的确能够理解为 AndroidAutoSize 是 AndroidAutoLayout 的升级版,可是它是我写的,关注一波呗
但 AndroidAutoSize 和 AndroidAutoLayout 的原理,却天差地别,好比 AndroidAutoLayout 只能使用 px 做为布局单位,而 AndroidAutoSize 刚好相反,在布局中 dp、sp、pt、in、mm 全部的单位都能支持,惟独不支持 px,但这也意味着 AndroidAutoSize 和 AndroidAutoLayout 在项目中能够共存,互不影响,因此使用 AndroidAutoLayout 的老项目也能够放心的引入 AndroidAutoSize,慢慢的完成屏幕适配框架的切换
之因此将框架取名为 AndroidAutoSize,第一,是想致敬 AndroidAutoLayout 对 Android 屏幕适配领域的贡献,第二,也想成为在 Android 屏幕适配领域有重要影响力的框架
我在上面就已经说了不少开源框架以及解决方案,只是把 今日头条屏幕适配方案 简单的封装成一个工具类而后引入项目,这时不少人就会说了 今日头条屏幕适配方案 官方公布的所有代码都只有 30 行不到,你不把它封装成工具类,那封装成什么?该怎么封装?下面就来看看 AndroidAutoSize 的总体结构
├── external │ ├── ExternalAdaptInfo.java │ ├── ExternalAdaptManager.java │── internal │ ├── CancelAdapt.java │ ├── CustomAdapt.java │── unit │ ├── Subunits.java │ ├── UnitsManager.java │── utils │ ├── AutoSizeUtils.java │ ├── LogUtils.java │ ├── Preconditions.java │ ├── ScreenUtils.java ├── ActivityLifecycleCallbacksImpl.java ├── AutoAdaptStrategy.java ├── AutoSize.java ├── AutoSizeConfig.java ├── DefaultAutoAdaptStrategy.java ├── DisplayMetricsInfo.java ├── FragmentLifecycleCallbacksImpl.java ├── InitProvider.java
AndroidAutoSize 根据 今日头条屏幕适配方案 官方公布的 30 行不到的代码,通过不断的优化和扩展,发展成了如今拥有 18 个类文件,近 2000 行代码的全面性屏幕适配框架,在迭代的过程当中完善和优化了不少功能,相比 今日头条屏幕适配方案 官方公布的原始代码,AndroidAutoSize 更加稳定、更加易用、更增强大,欢迎阅读源码,注释很是详细哦!
AndroidAutoSize 在使用上很是简单,只须要填写设计图尺寸这一步便可接入项目,但须要注意的是,AndroidAutoSize 有两种类型的布局单位能够选择,一个是 主单位 (dp、sp),一个是 副单位 (pt、in、mm),两种单位面向的应用场景都有不一样,也都有各自的优缺点
你们能够根据本身的应用场景在 主单位 和 副单位 中选择一个做为布局单位,建议想引入老项目而且注重稳定性的人群使用 副单位,只是想试试本框架,随时可能切换为其余屏幕适配方案的人群使用 主单位
其实 AndroidAutoSize 能够同时支持 主单位 和 副单位,但 AndroidAutoSize 能够同时支持 主单位 和 副单位 的目的,只是为了让使用者能够在 主单位 和 副单位 之间灵活切换,由于切换单位的工做量可能很是巨大,不能当即完成,但领导又要求立刻打包上线,这时就能够起到一个很好的过渡做用
主单位 的 Demo 在 demo
将 AndroidAutoSize 引入项目后,只要在 app 的 AndroidManifest.xml 中填写上设计图尺寸,无需其余过多配置 (若是你没有其余自定义需求的话),AndroidAutoSize 便可自动运行,像下面这样👇
<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>
在使用主单位时,design_width_in_dp
和 design_height_in_dp
的单位必须是 dp,若是设计师给你的设计图,只标注了 px 尺寸 (如今已经有不少 UI 工具能够自动标注 dp 尺寸了),那请自行根据公式 dp = px / (DPI / 160) 将 px 尺寸转换为 dp 尺寸,若是你不知道 DPI 是多少?那请以本身测试机的 DPI 为准,若是连怎么获得设备的 DPI 都不知道?百度吧好伐,若是你实在找不到设备的 DPI 那就直接将 px 尺寸除以 3 或者 2 也是能够的
若是你只是想使用 AndroidAutoSize 的基础功能,AndroidAutoSize 的使用方法在这里就结束了,只须要上面这一步,便可帮助你以最简单的方式接入 AndroidAutoSize,可是做为一个全面性的屏幕适配框架,在保证基础功能的简易性的同时,也必须保证复杂的需求也能在框架内被解决,从而达到一个小闭环,因此下面介绍的内容全是前人踩坑踩出来的一些必备功能,若是你没这个需求,或者以为麻烦,能够按需查看或者跳过,下面的内容建议和 Demo 配合起来阅读,效果更佳
design_width_in_dp
和 design_height_in_dp
虽然都须要填写,可是 AndroidAutoSize 只会将高度和宽度其中的一个做为基准进行适配,一方做为基准,另外一方就会变为备用,默认以宽度为基准进行适配,能够经过 AutoSizeConfig#setBaseOnWidth(Boolean) 不停的切换,这意味着最后运行到设备上的布局效果,在高度和宽度中只有一方能够和设计图上如出一辙,另一方会和设计图出现误差,为何不像 AndroidAutoLayout 同样,高和宽都以设计图的效果等比例完美呈现呢?这也很简单,你没法保证全部设备的高宽比例都和你设计图上的高宽比例一致,特别是在如今全面屏全面推出的状况下,若是这里不这样作的话,当你的项目运行在与设计图高宽比例不一致的设备上时,布局会出现严重的变形,这个概率很是大,详情请看 这里 不少人有疑惑,为何使用者只须要在 AndroidManifest.xml 中填写一下 meta-data 标签,其余什么都不作,AndroidAutoSize 就能自动运行,并在 App 启动时自动解析 AndroidManifest.xml 中填写的设计图尺寸,这里不少人不敢相信,问我真的只须要填写下设计图尺寸框架就能够正常运行吗?难道使用了什么 黑科技?
其实这里并无用到什么 黑科技,原理反而很是简单,只须要声明一个 ContentProvider,在它的 onCreate 方法中启动框架便可,在 App 启动时,系统会在 App 的主进程中自动实例化你声明的这个 ContentProvider,并调用它的 onCreate 方法,执行时机比 Application#onCreate 还靠前,能够作一些初始化的工做,get 到了吗?
这里须要注意的是,若是你的项目拥有多进程,系统只会在主进程中实例化一个你声明的 ContentProvider,并不会在其余非主进程中实例化 ContentProvider,若是在当前进程中 ContentProvider 没有被实例化,那 ContentProvider#onCreate 就不会被调用,你的初始化代码在当前进程中也就不会执行,这时就须要在 Application#onCreate 中调用下 ContentProvider#query 执行一下查询操做,这时 ContentProvider 就会在当前进程中实例化 (每一个进程中只会保证有一个实例),因此应用到框架中就是,若是你须要在多个进程中都进行屏幕适配,那就须要在 Application#onCreate 中调用 AutoSize#initCompatMultiProcess 方法
虽然 AndroidAutoSize 不须要其余过多的配置,只须要在 AndroidManifest.xml 中填写下设计图尺寸就能正常运行,但 AndroidAutoSize 仍是为你们准备了不少可配置选项,尽最大可能知足你们平常开发中的全部扩展需求
全部的全局配置选项在 Demo 中都有介绍,每一个 API 中也都有详细的注释,在这里就不过多介绍了
在 AndroidManifest.xml 中填写的设计图尺寸,是整个项目的全局设计图尺寸,可是若是某些 Activity 页面因为某些缘由,设计师单独出图,这个页面的设计图尺寸和在 AndroidManifest.xml 中填写的设计图尺寸不同该怎么办呢?不要急,AndroidAutoSize 已经为你考虑好了,让这个页面的 Activity 实现 CustomAdapt 接口便可实现你的需求,CustomAdapt 接口的第一个方法能够修改当前页面的设计图尺寸,第二个方法能够切换当前页面的适配基准,下面的注释都解释的很清楚
public class CustomAdaptActivity extends AppCompatActivity implements CustomAdapt { /** * 是否按照宽度进行等比例适配 (为了保证在高宽比不一样的屏幕上也能正常适配, 因此只能在宽度和高度之中选择一个做为基准进行适配) * * @return {@code true} 为按照宽度进行适配, {@code false} 为按照高度进行适配 */ @Override public boolean isBaseOnWidth() { return false; } /** * 这里使用 iPhone 的设计图, iPhone 的设计图尺寸为 750px * 1334px, 高换算成 dp 为 667 (1334px / 2 = 667dp) * <p> * 返回设计图上的设计尺寸, 单位 dp * {@link #getSizeInDp} 须配合 {@link #isBaseOnWidth()} 使用, 规则以下: * 若是 {@link #isBaseOnWidth()} 返回 {@code true}, {@link #getSizeInDp} 则应该返回设计图的总宽度 * 若是 {@link #isBaseOnWidth()} 返回 {@code false}, {@link #getSizeInDp} 则应该返回设计图的总高度 * 若是您不须要自定义设计图上的设计尺寸, 想继续使用在 AndroidManifest 中填写的设计图尺寸, {@link #getSizeInDp} 则返回 {@code 0} * * @return 设计图上的设计尺寸, 单位 dp */ @Override public float getSizeInDp() { return 667; } }
若是某个 Activity 想放弃适配,让这个 Activity 实现 CancelAdapt 接口便可,好比修改 density 影响到了老项目中的某些 Activity 页面的布局效果,这时就可让这个 Activity 实现 CancelAdapt 接口
public class CancelAdaptActivity extends AppCompatActivity implements CancelAdapt { }
Fragment 的自定义方式和 Activity 是同样的,只不过在使用前须要先在 App 初始化时开启对 Fragment 的支持
AutoSizeConfig.getInstance().setCustomFragment(true);
实现 CustomAdapt
public class CustomAdaptFragment extends Fragment implements CustomAdapt { @Override public boolean isBaseOnWidth() { return false; } @Override public float getSizeInDp() { return 667; } }
实现 CancelAdapt
public class CancelAdaptFragment extends Fragment implements CancelAdapt { }
在使用主单位时可使用 ExternalAdaptManager 来实如今不修改三方库源码的状况下,适配三方库的全部页面 (Activity、Fragment)
因为 AndroidAutoSize 要求须要自定义适配参数或取消适配的页面必须实现 CustomAdapt、CancelAdapt,这时问题就来了,三方库是经过远程依赖的,咱们没法修改它的源码,这时咱们怎么让三方库的页面也能实现自定义适配参数或取消适配呢?别急,这个需求 AndroidAutoSize 也已经为你考虑好了,固然不会让你将三方库下载到本地而后改源码!
须要注意的是 ExternalAdaptManager 的方法虽然能够添加任何类,可是只能支持 Activity、Fragment,而且 ExternalAdaptManager 是支持链式调用的,以便于持续添加多个页面
固然 ExternalAdaptManager 不只能够对三方库的页面使用,也可让本身项目中的 Activity、Fragment 不用实现 CustomAdapt、CancelAdapt 便可达到自定义适配参数和取消适配的功能
前面已经介绍了 副单位 的应用场景,这里就直接介绍 副单位 如何使用,副单位 的 Demo 在 demo-subunits
首先和 主单位 同样也须要先在 app 的 AndroidManifest.xml 中填写上设计图尺寸,但和 主单位 不同的是,当在使用 副单位 时 design_width_in_dp
和 design_height_in_dp
的单位不须要必定是 dp,能够直接填写设计图的 px 尺寸,在布局文件中每一个控件的大小也能够直接填写设计图上标注的 px 尺寸,无需再将 px 转换为 dp,这是 副单位的 特性之一,能够帮助你们提升开发效率
<manifest> <application> <meta-data android:name="design_width_in_dp" android:value="1080"/> <meta-data android:name="design_height_in_dp" android:value="1920"/> </application> </manifest>
因为 AndroidAutoSize 提供了 pt、in、mm 三种类型的 副单位 供使用者选择,因此在使用 副单位 时,还须要在 APP 初始化时,经过 UnitsManager#setSupportSubunits(Subunits) 方法选择一个你喜欢的副单位,而后在布局文件中使用这个副单位进行布局,三种类型的副单位,其实效果都是同样,你们按喜欢的名字选择便可
因为使用副单位是为了完全屏蔽修改 density 所形成的对三方库页面、三方库控件以及系统控件的布局效果的影响,因此在使用副单位时建议调用 UnitsManager#setSupportDP(false) 和 UnitsManager#setSupportSP(false),关闭 AndroidAutoSize 对 dp 和 sp 的支持,AndroidAutoSize 为何不在使用 副单位 时默认关闭对 dp、sp 的支持?由于容许同时支持 主单位 和 副单位 能够帮助使用者在 主单位 和 副单位 之间切换时更好的过渡,这点在前面就已经提到过
UnitsManager 的详细使用方法,在 demo-subunits 中都有展现,注释也十分详细
在使用 副单位 时自定义 Activity 和 Fragment 的方式是和 主单位 是同样的,这里就再也不过多介绍了
若是你的项目在使用 副单位 而且关闭了对 主单位 (dp、sp) 的支持,这时 ExternalAdaptManager 对三方库的页面是不起做用的,只对本身项目中的页面起做用,除非三方库的页面也使用了副单位 (pt、in、mm) 进行布局
其实 副单位 之因此能完全屏蔽修改 density 所形成的对三方库页面、三方库控件以及系统控件的布局效果的影响,就是由于三方库页面、三方库控件以及系统控件基本上使用的都是 dp、sp 进行布局,因此只要 AndroidAutoSize 关闭了对 dp、sp 的支持,转而使用 副单位 进行布局,就能完全屏蔽修改 density 所形成的对三方库页面、三方库控件以及系统控件的布局效果的影响
但这也一样意味着使用 副单位 就不能适配三方库的页面了,ExternalAdaptManager 也就对三方库的页面不起做用了
在开发阶段布局时的实时预览是一个很重要的环节,不少状况下 Android Studio 提供的默认预览设备并不能彻底展现咱们的设计图,因此咱们就须要本身建立模拟设备,dp、pt、in、mm 这四种单位的模拟设备建立方法请看 这里
AndroidAutoSize 在经历了 240+ commit、60+ issues、6 个版本 的洗礼后,逐渐的稳定了下来,已经在上个星期发布了首个正式版,在这里要感谢将 AndroidAutoSize 接入到本身项目中的上千个使用者,感谢他们的信赖,AndroidAutoSize 建立的初衷就是为了让全部使用 今日头条屏幕适配方案 的使用者能有一个能够一块儿交流、沟通的汇集地,因此后面也会持续的收集并解决 今日头条屏幕适配方案的常见问题,让 今日头条屏幕适配方案 变得更加成熟、稳定
至此本系列的第三篇文章也就完结了,这也预示着这个系列连载的终结,这篇文章建议结合系列的第一篇文章 骚年你的屏幕适配方式该升级了!(一)-今日头条适配方案 一块儿看,这样能够对 今日头条屏幕适配方案 有一个更深刻的理解,若是你能将整个系列的文章都所有认真看完,那你对 Android 屏幕适配领域的相关知识绝对会有一个飞速的提高!
当你的项目须要切换某个框架时,你会怎么去考察、分析、对比现有的开源方案,并有足够的理由去选择或优化一个最适合本身项目的方案呢?其实整个系列文章能够看做是我怎么去选择同类型开源方案的过程,你之后当遇到一样的选择也能够参照个人思惟方式去处理,固然若是之后面试官问到你屏幕适配相关的问题,你能将我如何选择、分析、对比已有方案的过程以及文章中的核心知识点告诉给面试官,那确定比你直接说一句我使用的是某某开源库有价值得多
如下是 骚年你的屏幕适配方式该升级了! 系列文章,欢迎转发以及分享:
Hello 我叫 JessYan,若是您喜欢个人文章,能够在如下平台关注我
-- The end