前言
在写一个功能时用到了动态加载 merge 标签的布局 由于原来都是直接在xml 用 include 直接使用 没有在代码里使用过 也没有仔细的了解过原理,所以直接掉坑里了 直接是用了平常布局的
var view = LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,null)
layout.addView(view)
来使用 结果一运行到这段代码就崩溃了,然后就仔细的了解了一下 merge 原理 请看下文:
merge简介
merge标签是用来减少ui层级,优化布局的。
merge在一般情况下是用来配合include使用的
如下:
layout_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/app_bg"
android:gravity="center_horizontal">
<include layout="@layout/title"/>
</LinearLayout>
layout_title.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/delete"/>
</merge>
这样使用的。 merge标签是怎么来减少层级的呢 ,在LayoutInflater的inflate()函数中解析时 发现解析的是 merge标签时会把merge 里的子元素直接添加到 merge的 父控件里 这样就减少了一个没有比较的容器控件了。 而且 merge 标签必须是根元素
merge遇到的坑
1.
在使用merge时给标签设置id 然后再代码里用findViewById去获取这个id view时 会出现崩溃的情况,这就是因为是用merge标签 在 LayoutInflater的inflate()函数中时直接将其中的子元素添加到了 merge 标签的 parent 中了,而merge 因为只是一个标签 所以是没有添加到 parent 里的,所以在运行时就没有这个merge 所以就会报错。
在代码中通过代码添加 merge 标签布局 最先的时候是
var frameLayout =getView<FrameLayout>(R.id.fl_content)
if (!::view.isInitialized){
setConentLayout(LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,null))
}
frameLayout?.addView(view,frameLayout.layoutParams )
但是一运行这代码就会崩溃 这个是候用debug看了 在哪行代码发生的错误 是在
setConentLayout(LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,null))
2.
这里发生的错误,查看了一下源码 发现是因为inflate()函数中 添加的布局是 merge 布局是需要添加 在inflate()函数中传入 ViewGroup
因为在LayoutInflater 的inflate函数中有这个判断 当解析的是 merge标签时 如果这个 ViewGroup 为null 或attachToRoot 为false 就会直接抛出错误
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
}
解决了这个问题 代码改成这样
var frameLayout =getView<FrameLayout>(R.id.fl_content)
if (!::view.isInitialized){
setConentLayout(LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,frameLayout,true))
}
frameLayout?.addView(view,frameLayout.layoutParams )
我本以为程序就可以愉快的跑下去了
3.但是我在一次运行时又报错了 这次错误是在
frameLayout?.addView(view,frameLayout.layoutParams )
这一行里 ,但是我找了半天也没有找到问题所在 ,然后仔细看了一下源代码 发现是因为 在
LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,frameLayout,true)
的时候其实 merge 布局里的元素就已经添加进布局了 而且 这个返回的 View 就是我们传入的 ViewGroup 所以我的这段代码 就是 把自己添加进自己 所以报错了
最后我改成以下代码就ok了
var frameLayout =getView<FrameLayout>(R.id.fl_content)
if (!::view.isInitialized){
setConentLayout(LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,frameLayout,true))
}
引用www.jianshu.com/p/cf3751333… www.androidchina.net/2485.html