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