AutoLayout源码解析(1)
鸿神的AutoLayout堪称适配终结者,虽然项目已经不再维护,对于一些好的框架和实现原理我们还是有学习意义的!现在让我们一起来学习AutoLayout的源码吧!
首先我们应该思考这样一个问题:对于一个框架如何去学习呢?
难道是下载源码后,一个类一个类的去看吗? 这肯定不行,这样会浪费大量的时间,而且还不一定能很好的理解他
正确的流程应该是从如何去使用入手,然后根据调用流程一步一步的去理解,这样就能很好的理解框架的整个流程了!
现在让我们来看一下AutoLayout的使用流程:
1、将Autolayout添加到我们的项目依赖中
dependencies {// 其他依赖// ...implementation 'com.zhy:autolayout:1.4.5'
}
2、在AndroidManifest.xml标明设计稿尺寸
<!--ui设计稿提供的手机尺寸-->
<meta-data android:name="design_width" android:value="768"/>
<meta-data android:name="design_height" android:value="1280"/>
3、在Application中进行初始化
AutoLayoutConifg.getInstance().useDeviceSize().init(this);
4、让你的Activity继承AutoLayoutActivity或者直接在xml使用AutoLinearLayout、AutoRelativeLayout、AutoFrameLayout
首先出现在我们眼前的有AutoLayoutConifg、AutoLayoutActivity、AutoLinearLayout、AutoRelativeLayout、AutoFrameLayout这些类
那我们就按顺序分别去看这些类做了那些事情
1、AutoLayoutConifg
首先这是一个单例类
private static AutoLayoutConifg sIntance = new AutoLayoutConifg();private AutoLayoutConifg()
{
}public static AutoLayoutConifg getInstance()
{return sIntance;
}
它有这些属性
// 屏幕的宽度
private int mScreenWidth;
// 屏幕的高度
private int mScreenHeight;
// 设计图的宽度
private int mDesignWidth;
// 设计图的高度
private int mDesignHeight;
// 暂时不知道这个参数是啥,字面意思是使用设备大小
private boolean useDeviceSize;
接下来我们来看init里面做了啥
public void init(Context context)
{// 通过方法名我们猜想应该是从AndroidManifest读取MetaData里面的设计尺寸getMetaData(context);// 这里是获取实际屏幕的大小,传入了useDeviceSize属性 int[] screenSize = ScreenUtils.getScreenSize(context, useDeviceSize);// 给mScreenWidth赋值mScreenWidth = screenSize[0];// 给mScreenHeight赋值mScreenHeight = screenSize[1];L.e(" screenWidth =" + mScreenWidth + " ,screenHeight = " + mScreenHeight);
}
接下来我们来看getMetaData方法里的代码
private void getMetaData(Context context)
{PackageManager packageManager = context.getPackageManager();ApplicationInfo applicationInfo;try{applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);if (applicationInfo != null && applicationInfo.metaData != null){// 给mDesignWidth赋值mDesignWidth = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH);// 给mDesignHeight赋值mDesignHeight = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT);}} catch (PackageManager.NameNotFoundException e){throw new RuntimeException("you must set " + KEY_DESIGN_WIDTH + " and " + KEY_DESIGN_HEIGHT + " in your manifest file.", e);}L.e(" designWidth =" + mDesignWidth + " , designHeight = " + mDesignHeight);
}
这里印证了我们的猜想:这个方法就是从AndroidManifest读取MetaData里面的设计尺寸,然后赋值给属性[mDesignWidth、mDesignHeight]
接下来我们看 ScreenUtils.getScreenSize(context, useDeviceSize)方法是如何获取真实的屏幕大小,顺便确定useDeviceSize属性的意思
int[] size = new int[2];// 这部分的代码是获取屏幕宽高的代码,有多种写法,写法也比较固定WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display d = w.getDefaultDisplay();DisplayMetrics metrics = new DisplayMetrics();d.getMetrics(metrics);int widthPixels = metrics.widthPixels;int heightPixels = metrics.heightPixels;// since SDK_INT = 1;if (!useDeviceSize){size[0] = widthPixels;size[1] = heightPixels - getStatusBarHeight(context);return size;}
我们看红色注释部分,可以看到从SDK1开始,只有useDeviceSize为false才会走进来
// includes window decorations (statusbar bar/menu bar)if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)try{widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);} catch (Exception ignored){}// includes window decorations (statusbar bar/menu bar)if (Build.VERSION.SDK_INT >= 17)try{Point realSize = new Point();Display.class.getMethod("getRealSize", Point.class).invoke(d,realSize);widthPixels = realSize.x;heightPixels = realSize.y;} catch (Exception ignored){}size[0] = widthPixels;size[1] = heightPixels;return size;
可以看到接下来部分的代码都不同版本的适配代码,所以我们可以这样理解useDeviceSize:根据版本来适配获取屏幕真实宽高的,所以当我们项目的最低版本大于等于14时,应该在Application里面去将useDeviceSize配置为true。因为现在构建工程的最低版本基本都是19或21了,所以应该将useDeviceSize设置为true。
那么如果我们不设置会出现什么问题呢?
通过DisplayMetrics获取到的heightPixels的值在高版本中是已经减去了状态栏高度的,而代码里面又减了一次状态栏高度,会导致减去了2次状态栏的高度,从而导致适配的缩放比例存在误差
其实看完这个类如果我们善于思考的话,已经能够猜到它的大致原理了
比如设计图上有一个384px*640px的View,设计图是768x1280,我们的手机分辨率是1440x3168,所以:
mScreenWidth = 1440;
mScreenHeight = 3168;
mDesignWidth = 768;
mDesignHeight = 1280;
可以看到设计图上这个View占用了屏幕的4分之1,我们要在1440x3168的屏幕上也显示4分之1,怎么办呢?
我们用1440*384/760 = 720,3168*640/1280 = 1584,所以我们想要在1440x3168的屏幕上显示相同的效果这个控件的大小应该是720px*1584px,目前大致能想到是就这么多了,接下来我们继续看源码是如何实现的!
AutoLayout源码解析(1)相关推荐
- 谷歌BERT预训练源码解析(二):模型构建
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...
- 谷歌BERT预训练源码解析(三):训练过程
目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...
- 谷歌BERT预训练源码解析(一):训练数据生成
目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...
- Gin源码解析和例子——中间件(middleware)
在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...
- Colly源码解析——结合例子分析底层实现
通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...
- libev源码解析——定时器监视器和组织形式
我们先看下定时器监视器的数据结构.(转载请指明出于breaksoftware的csdn博客) /* invoked after a specific time, repeatable (based o ...
- libev源码解析——定时器原理
本文将回答<libev源码解析--I/O模型>中抛出的两个问题.(转载请指明出于breaksoftware的csdn博客) 对于问题1:为什么backend_poll函数需要指定超时?我们 ...
- libev源码解析——I/O模型
在<libev源码解析--总览>一文中,我们介绍过,libev是一个基于事件的循环库.本文将介绍其和事件及循环之间的关系.(转载请指明出于breaksoftware的csdn博客) 目前i ...
- libev源码解析——调度策略
在<libev源码解析--监视器(watcher)结构和组织形式>中介绍过,监视器分为[2,-2]区间5个等级的优先级.等级为2的监视器最高优,然后依次递减.不区分监视器类型和关联的文件描 ...
- libev源码解析——监视器(watcher)结构和组织形式
在<libev源码解析--总览>中,我们介绍了libev的一些重要变量在不同编译参数下的定义位置.由于这些变量在多线程下没有同步问题,所以我们将问题简化,所提到的变量都是线程内部独有的,不 ...
最新文章
- 【唠叨两句】如何将一张树型结构的Excel表格中的数据导入到多张数据库表中...
- 为什么现在改用int.TryParse了
- php call_user_func_array 性能,php-call_user_func_array是否太慢?
- 一个地址或二维码自动识别设备,并跳转到各自相应的下载地址,兼容微信
- SpringBoot(六)_AOP统一处理请求
- mysql类型设计_mysql设计表结构数据类型的选择
- GCD LCM UVA - 11388 (思维。。水题)
- 用python做mud
- Win7 路由上网DNS服务器ping不通的解决方法
- lodop打印html内容,Lodop打印控件在页面如何使用
- Java 7:项目代币中的代码示例
- CORS error 状态码451
- Python笔记-函数装饰器的缺点
- [Angularjs]angular ng-repeat与js特效加载先后导致的问题
- 4月第3周业务风控关注 | 文化部再次审查直播和游戏产品,已下架4939款直播应用...
- ajax同步导致ajax上面的代码不执行?
- winform定义数据源名称_WinForm中使用CrystalReport水晶报表——基础,分组统计,自定义数据源...
- model 字段参数 choice
- MiPony– 杀手级免费网盘下载工具 可挂机下载支持YunFile
- 用PPT就可以做印章?是的,超简单超逼真,教你一分钟搞定