天天看点

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

本来是完整一份的,结果一页写不下,分页,感觉知乎显示效果不行,来,点我博客查看

本文主要介绍:LayoutInflater

本文适合对象:打算搞懂LayoutInflater的inflate的开发者

本文字数:约2.5万,阅读时间:约2H

问题

先从表象入手

在Android开发过程中,很多地方都不可避免的使用到inflate方法,如在使用

RecycleView

的时候构建

ViewHolder

对象,给

Fragment

进行

CreateView

我们通常是

inflater.inflate(R.layout.xxx, container, false)

或者

LayoutInflater.from(parent.context).inflate(R.layout.xxx, parent, false)

来调用inflate方法的,不难发现,inflate方法的作用是将一个

xml

布局文件变成一个

view

对象。然而仅仅是根据模板,按照固定的"规律"去修改某些参数来实现目标,只能叫做是「使用」而已

那么,我们就来将它「分解」成明确的「问题」,来具体的「学习」吧

  1. LayoutInflater

    inflater

    这些语句的「头部」是什么?怎么来的?
  2. inflate

    方法的「参数」是什么意思,有什么用?
  3. 这些语句是怎么实现转换 xml view 的?
  4. 我除了常见的用法还能怎么用它

Question One:「头部」

官方文档

思考的First Step,问其所来

官方文档对

LayoutInflater

的说明如下:

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

简单的翻译过来就是:

  1. 这玩意是用来将 xml 转换为 view
  2. 这玩意不能直接new初始化,通过

    Activity

    SystemService

    获取,你也可以自定义他的工厂方法
  3. 因为性能问题,他只能把写在layout里被预处理过的 xml 转换为 view ,不能随便找个xml文件就让他转换

回归表象

那好了,第一个问题解决了,

LayoutInflater

是一个不能直接new的类,他来管

xml

转换为

view

,我们在

adapter

里通过

LayoutInflater.from(context)

获取实例,

fragment

则是直接使用了

FragmentManager

调用

Fragment.onCreateView

的时候传过来的

inflater

对象

Question Two:「方法」

inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)

方法有三个参数,第一个参数很好理解,就是前文所说的,

xml

转换为

view

layout xml

对应的资源ID。第二第三个参数又什么意思呢?我转换成View为什么需要它呢?

官方文档

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

简单翻译:

  1. root是要转换的 xml 将要存在的外部

    ViewGroup

  2. xml 转换成 view 后要不要

    addView

    root

    (

    ViewGroup

    )

这是个啥意思呢,看了之后似懂非懂,我还是一脸懵逼。

测试

纸上学来终觉浅,只是看文档还是不行,不如自己上手试试,把自己脑子里的可能性都弄出来试试看效果,跑出来啥样就是啥样了。

按排列组合来说,我们一共有四种(如果你想到更多可能性,不妨自己写出来跑跑看)

  1. root = null, attachToRoot = false
  2. root = null, attachToRoot = true
  3. root = viewgroup, attachToRoot = false
  4. root = viewgroup, attachToRoot = true

接下来我们一个个实验,实验的过程为,通过

activity

getLayoutInflater()

方法获取

inflater

对象,调用其

inflate

方法,传递不同的参数,将得到的

view

添加到

activity

布局的

viewgroup

中,查看结果。

首先是布局展示,

activity

的布局只有一个蓝底的ViewGroup,而要加载的

view

也只是一个黄色的View

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)
activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

注意我给蓝底加了一句

android:paddingTop="32dp"

,黄底加了一句

android:layout_margin="4dp"

测试①

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

我们看到黄色的

view

几乎填满了整个

activity

view

width

height

margin

都无效,但是

viewgroup

padding

是有效的。

但是我们还不能确定是

root = null

attachToRoot = false

中哪个的原因,我们继续测试

测试②

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

我们可以看到黄色的

view

里面设置的

width

height

margin

还是无效的,但是

viewgroup

padding

是有效的。

通过这两个测试,我猜测

root

的效果是控制

xml

里关于

layoutparam

的设置是否有效,但是不是这样还要看接下来的测试。而

viewgroup

的padding参数是不受影响的,这个也好理解,因为是ViewGroup的属性,在onDraw方法里处理的。

测试③

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

我们可以看到黄色的

view

里面设置的

width

height

margin

也都有效了

也就是说,root的猜测基本是坐实了,接下来就剩

attachToRoot

还是一头雾水了

测试④

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

Crash!出问题了,看看报错信息:

The specified child already has a parent. You must call removeView() on the child's parent first.

这娃儿已经有个爹了,你要当他爹得先让他现在的爹

removeView()

啥意思,已经有个爹了?这爹是谁,他转换的过程也就接触到一个viewgroup啊,难道说

attachToRoot = true

的话就直接

addView()

了?试试看

测试⑤

activity调用fragment的方法_从inflate方法开始,搞懂LayoutInflater的inflate过程(上)

果然和我们想的一样……那么,可以总结一下了

总结

  1. root

    参数将决定

    view

    layoutparam

    ,如果为null,那

    xml

    里定义的最外层

    view

    layoutparam

    将全部无效
  2. attachToRoot

    表示是否需要一键

    addView()

    ,如果

    root

    为null,那这个参数将被自动忽略
下篇

继续阅读