android merge標籤 的使用 和 遇到的坑

前言

在寫一個功能時用到了動態加載  merge 標籤的佈局  因爲原來都是直接在xml 用 include 直接使用  沒有在代碼裏使用過  也沒有仔細的瞭解過原理,因此直接掉坑裏了   直接是用了日常佈局的
複製代碼
var view =     LayoutInflater.from(mContext)
.inflate(R.layout.dialog_commom_default_content,null)

layout.addView(view)
複製代碼

來使用 結果一運行到這段代碼就崩潰了,而後就仔細的瞭解了一下 merge 原理 請看下文:html

merge簡介

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遇到的坑

1.

在使用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))
複製代碼

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);
}
複製代碼

解決了這個問題 代碼改爲這樣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

3.可是我在一次運行時又報錯了 此次錯誤是在

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

相關文章
相關標籤/搜索