前言
很高兴见到你~
今天要和大家分享的是LayoutInflater。我起了名字。这是布局泵。形象很好。其实是根据英语翻译过来的。(大卫亚设)。
我们知道气球打气筒可以给气球打气从而改变它的形状。而布局打气筒的作用就是给我们的 Xml 布局打气让它变成一个个 View 对象。在我们的日常工作中,经常会接触到他,因为只要你写了 Xml 布局,你就要使用 LayoutInflater,下面我们就来好好讲讲它。
注意:本文所展示的系统源码都是基于Android-30 ,并提取核心部分进行分析
一、基本使用
1、LayoutInflater 实例获取
1)、通过 LayoutInflater 的静态方法 from 获取
2)、通过系统服务 getSystemService 方法获取
3)、如果是在 Activity 或 Fragment 可直接获取到实例
//1、通过 LayoutInflater 的静态方法 from 获取
val layoutInflater: LayoutInflater = Layou(this)
//2、通过系统服务 getSystemService 方法获取
val layoutInflater: LayoutInflater = getSystemService) as LayoutInflater
//3、如果是在 Activity 或 Fragment 可直接获取到实例
layoutInflater //相当于调用 getLayoutInflater()
复制代码
实际上,1 是 2 的简单写法,只是 Android 给我们做了一下封装。拿到 LayoutInflater 实例后,我们就可以调用它的 inflate 系列方法了,这几个方法是本篇文章的一个重点,如下:
image-20210622163719911
从 Xml 布局到创建 View 对象,这几个方法扮演着至关重要的作用,其中我们用的最多就是第一个和第三个重载方法,现在我们就来使用一下
二、例子
1、创建一个新项目,MainActivity 对应的布局如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.con
xmlns:android=";
xmlns:tools=";
android:id="@+id/cons_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"/>
复制代码
2、创建一个新的布局取名 i,如下图:
image-20210622174620878
3、修改 MainActivity 中的代码
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
(savedInstanceState)
setContentView)
val consMain = findViewById<ConstraintLayout>)
val itemMain = layou, null)
con(itemMain)
}
}
复制代码
上述代码我们使用了两个参数的 inflate 重载方法,第二个参数 root 传了一个 null ,然后把当前布局添加到 Activity 中,运行看下效果:
啥情况?怎么和预想的不一样呢?我的背景颜色怎么不见了?把这个问题 1 先记着
接下来,我们修改一下 MainActivity 中的代码,如下:
val itemMain = layou, consMain)
//等同下面这行代码
val itemMain = layou, consMain,true)
复制代码
实际上上面这句代码就相当于调用了三个参数的重载方法,且第三个参数为 true,我们看下它两个参数的源码:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
复制代码
现在在运行看下结果:
报错了,提示我们当前 child 已经有了一个父 View,你必须先调用父 View 的 removeView 方法移除当前 child 才行。是不是疑问更多了呢?把这个问题 2 也先记着
我们在修改一下 MainActivity 中的代码,如下:
val itemMain = layou, consMain,false)
复制代码
在运行看下结果:
image-20210622190835239
嗯,现在达到了我们预期的效果
现在回到上面那两个问题,分析发现是 LayoutInflater inflate 方法传了不同的参数导致的,那这些参数到底有什么玄乎的地方呢?接下来跟着我的脚步分析下源码,或许你就豁然开朗了
三、LayoutInflater inflate 系列方法源码分析
在分析源码之前,我们需要明白一些基础知识:
我们一般都会使用 layout_width 和 layout_height 来设置 View 的大小,实际上是要满足一个条件,那就是这个 View 必须存在于一个容器或布局中,否则没有意义,之后如果将 layout_width 设置成 match_parent 表示让 View 的宽度填充满布局,如果设置成 wrap_content 表示让 View 的宽度刚好可以包含其内容,如果设置成具体的数值则 View 的宽度会变成相应的数值。这也是为什么这两个属性叫作 layout_width 和layout_height,而不是 width 和 height 。
明白了上面这些知识,我们继续往下看
实际上,我们调用 LayoutInflater inflate 系列方法,最终都会走到上述截图的第 4 个重载方法,看下它的源码,仅贴出关键代码:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
//...
//获取布局 Xml 里面的属性集合
AttributeSet attrs = Xml.asAttributeSet(parser);
// 将传入的 root 赋值 给 result
View result = root;
// 创建根 View 赋值给 temp
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
//...
//如果传入的 root 不为空,通过 root 和布局属性生成布局参数
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// 如果传入的 attachToRoot 为 false 则给当前创建的根 View 设置布局参数
(params);
}
}
//递归创建子 View 并添加到父布局中
rInflateChildren(parser, temp, attrs, true);
if (root != null && attachToRoot) {
//如果 root 不为空且 attachToRoot 为 true,添加当前创建的根 View 到 root
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
//如果 root 为空或者 attachToRoot 为 false, 将当前创建的根 View 赋值给 result
result = temp;
}
//...
//返回当前 result
return result;
}
}
复制代码
上述代码我们可以得到一些结论:
1、如果传入的 root 不为 null 且 attachToRoot 为 false,此时会给 Xml 布局生成的根 View 设置布局参数
注意:Xml 布局生成的根 View 并没有被添加到任何其他 View 中,此时根 View 的布局属性不会生效,但是我们给它设置了布局参数,那么它就会生效,只是没有被添加到任何其他 View 中
2、如果传入的 root 不为 null 且 attachToRoot 为 true,此时会将 Xml 布局生成的根 View 通过 addView 方法携带布局参数添加到 root 中
注意:此时 Xml 布局生成的根 View 已经被添加到其他 View 中,注意避免重复添加而报错
3、如果传入的 root 为 null ,此时会将 Xml 布局生成的根 View 对象直接返回
注意:此时 Xml 布局生成的根 View 既没有被添加到其他 View 中,也没有设置布局参数,那么它的布局参数将会失效
明白了上面这些知识点,我们在看下为啥为会出现之前那些问题
四、问题分析
1、问题 1
上述问题 1 实际上我们是调用了 LayoutInflater 两个参数的 inflate 重载方法:
inflate(@LayoutRes int resource, @Nullable ViewGroup root)
复制代码
传入的实参: resouce 传入了一个 Xml 布局,root 传入了 null
根据我们上面源码得到的结论,当传入的 root 为 null ,此时会将 Xml 布局生成的根 View 对象直接返回
那么此时这个布局根 View 不在任何 View 中,因此它的布局属性失效了,但是 TextView 在一个布局中,它的布局属性会生效,因此就出现了上述截图中的效果
2、问题 2
上述问题 2 我们调用的还是 LayoutInflater 两个参数的构造方法
传入的实参: resouce 传入了一个 Xml 布局,root 传入了 consMain
实际又会调用 LayoutInflater 三个参数的 inflate 重载方法:
inflate(@LayoutRes int resource, @Nullable ViewGroup root,boolean attachToRoot)
复制代码
此时传入实参变为:resouce 传入了一个 Xml 布局,root 传入了 consMain,attachToRoot 传入了 true
根据我们上面源码得到的结论:当传入的 root 不为 null 且 attachToRoot 为 true,此时会将 Xml 布局生成的根 View 通过 addView 方法携带布局参数添加到 root 中
此时我们在 MainActivity 中又重复调用了 addView 方法,因此就报那个错了。如果想不报错,把 MainActivity 中的那行 addView 去掉就可以了
3、预期效果
上述预期效果,我们调用的是 LayoutInflater 三个参数的 inflate 重载方法
传入的实参:resouce 传入了一个 Xml 布局,root 传入了 consMain,attachToRoot 传入了 false
根据我们上面源码得到的结论:当传入的 root 不为 null 且 attachToRoot 为 false,此时会给 Xml 布局生成的根 View 对象设置布局参数
此时根 View 的布局属性会生效,只不过没有被添加到任何 View 中,而又因为 MainActivity 中调用了 addView 方法,把当前根 View 添加了进去,所以达到了我们预期的效果
到这里,你是否明白了 LayoutInflater inflate 方法的应用了呢?
如果还有疑问,欢迎评论区给我提问,我们一起讨论
五、为啥 Activity 中布局根 View 的布局属性会生效?
看下面这张图:
注意:Android 版本号和应用主题会影响到 Activity 页面组成,这里以常见页面为例
image-20210622210219600
我们的页面中有一个顶级 View 叫 DecorView,DecorView 中包含一个竖直方向的 LinearLayout,LinearLayout 由两部分组成,第一部分是标题栏,第二部分是内容栏,内容栏是一个FrameLayout,我们在 Activity 中调用 setContentView 就是将 View 添加到这个FrameLayout 中。
看到这里你应该也明白了:Activity 中布局根 View 的布局属性之所以能生效,是因为 Android 会自动在布局文件的最外层再嵌套一个FrameLayout
六、总结
本篇文章重点内容:
1、 LayoutInflater inflate 方法参数的应用,记住下面这个规律:
- 当传入的 root 不为 null 且 attachToRoot 为 false,此时会给 Xml 布局生成的根 View 设置布局参数
- 当传入的 root 不为 null 且 attachToRoot 为 true,此时会将 Xml 布局生成的根 View 通过 addView 方法携带布局参数添加到 root 中
- 当传入的 root 为 null ,此时会将 Xml 布局生成的根 View 对象直接返回
2、Activity 中布局根 View 的布局属性会生效是因为 Android 会自动在布局文件的最外层再嵌套一个 FrameLayout
好了,本篇文章到这里就结束了,希望能给你带来帮助
感谢你阅读这篇文章
1.文章《打气筒怎么用?总结很全面速看!Android 布局打气筒:教你玩转 LayoutInflater》援引自互联网,为网友投稿收集整理,仅供学习和研究使用,内容仅代表作者本人观点,与本网站无关,侵删请点击页脚联系方式。
2.文章《打气筒怎么用?总结很全面速看!Android 布局打气筒:教你玩转 LayoutInflater》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
相关推荐
- . 现代买票为什么带上携程保险
- . 潮阳怎么去广州南站
- . 湖南马拉河怎么样
- . 烧纸为什么到三岔路口
- . 百色为什么这么热
- . 神州租车怎么样
- . 芜湖方特哪个适合儿童
- . 护肤品保养液是什么类目
- . 早晚的护肤保养有哪些项目
- . 女孩护肤品怎么保养的最好