android merge标签 的使用 和 遇到的坑

前言

在写一个功能时用到了动态加载  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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值