在寫一個功能時用到了動態加載 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