在写一个功能时用到了动态加载 merge 标签的布局 因为原来都是直接在xml 用 include 直接使用 没有在代码里使用过 也没有仔细的了解过原理,因此直接掉坑里了 直接是用了日常布局的
复制代码
var view = LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,null)
layout.addView(view)
复制代码
来使用 结果一运行到这段代码就崩溃了,而后就仔细的了解了一下 merge 原理 请看下文:html
merge标签是用来减小ui层级,优化布局的。
merge在通常状况下是用来配合include使用的
复制代码
以下:android
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 标签必须是根元素bash
在使用merge时给标签设置id 而后再代码里用findViewById去获取这个id view时 会出现崩溃的状况,这就是由于是用merge标签 在 LayoutInflater的inflate()函数中时直接将其中的子元素添加到了 merge 标签的 parent 中了,而merge 由于只是一个标签 因此是没有添加到 parent 里的,因此在运行时就没有这个merge 因此就会报错。app
在代码中经过代码添加 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))
复制代码
这里发生的错误,查看了一下源码 发现是由于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);
}
复制代码
解决了这个问题 代码改为这样ui
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 )
复制代码
我本觉得程序就能够愉快的跑下去了spa
frameLayout?.addView(view,frameLayout.layoutParams )
复制代码
这一行里 ,可是我找了半天也没有找到问题所在 ,而后仔细看了一下源代码 发现是由于 在.net
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