addView遇到的坑及其解決

   代碼中給容器動態添加子View時遇到一些問題,當時還是糾結許久的。擅總結者無敵,寫下此篇總結,問題比較的簡單,希望對新手有所幫助。

 

使用場景:

情況一:

View view = View.inflate(this, R.layout.item_contact,null);

view.getLayoutParams() == null

情況二:

View view =getLayoutInflater().inflate(R.layout.item_contact, null, false);

view.getLayoutParams() == null

情況三:

View view =getLayoutInflater().inflate(R.layout.item_contact, mContainer, false);

或者:View view =LayoutInflater.from(this).inflate(R.layout.item_contact, mContainer, false);

view.getLayoutParams() != null

 

//添加到指定父容器

mContainer.addView(view);

 

View.inflate(this, R.layout.item_contact, mContainer);

作用:創建一個指定佈局的View對象,並加入到mContainer的父容器中。

 

getLayoutInflater().inflate(R.layout.item_contact,mContainer, true);

作用:創建一個指定佈局的View對象,並加入到mContainer的父容器中。

 

View.inflate(this,resource, null);

這種方式創建的View對象沒有LayoutParams。沒指定父容器(null),也就是寬高參數是空的。

此時addView方法中會調用generateDefaultLayoutParams()生成默認的寬高參數:

就是:new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

如果你的原本佈局寬高不是wrap_content,wrap_content,那麼就有問題了。

 

LayoutInflater.inflate方法

LayoutInflater.inflate(int resource, ViewGroup root,boolean attachToRoot)

resource:資源文件id

root:父容器對象

attachToRoot:是否添加到父容器中

備註:

attachToRoot == true;root會作爲創建的View對象的父容器

attachToRoot == false;root會爲創建的View對象提供LayoutParams參數

 

對於新手而言,問題可能在於:

View view = View.inflate(this, R.layout.item_contact,null);

mContainer.addView(view);添加到mContainer父容器中

 

問題在於:此時的view是沒有LayoutParams的,需要:

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(

LinearLayout.LayoutParams.WRAP_CONTENT,

LinearLayout.LayoutParams.MATCH_PARENT);

需要使用:mContainer.addView(view, params);這樣才能正確體現View佈局的寬高參數。

上述代碼相當於如下:

View.inflate(this, R.layout.item_contact, mContainer);//一行代碼搞定

而同一個View對象,不能同時有兩個父容器,此時就無需再調用addView(view);添加了。

如果不需要對View對象進行操作,還免去創建引用變量的資源消耗。(這裏有坑)

 

另外一個類似方法:

getLayoutInflater().inflate(int resource, ViewGrouproot, boolean attachToRoot)

事實上,從源碼可見:

View.inflate(this, resource, null);//實現原理可歸納爲:

LayoutInflater.from(this).inflate(resource, root, root!= null);

 

總結:爲容器添加子View的方式:

方式一://方便重新指定LayoutParams

View view = View.inflate(this, R.layout.item_contact,null);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(...);//重新指定LayoutParams。

mContainer.addView(view, params);

方式二(同一):

View view =LayoutInflater.from(this).inflate(R.layout.item_contact, mContainer, false);

mContainer.addView(view);

 

方式三://適合於使用佈局中指定的LayoutParams

View.inflate(this, R.layout.item_contact, mContainer);

方式四(同四):

LayoutInflater.from(this).inflate(R.layout.item_contact,mContainer, true);

 

備註:顯然,方式三、四使用更簡潔,方式一、二則適用於佈局重用於不適合佈局中指定的LayoutParams的情況。

==================================================================================================

坑坑坑坑

LayoutInflater的API文檔:

View inflate (int resource, ViewGroup root)

The root View of the inflated hierarchy. If root was supplied, this is the root View; otherwise it is the root of the inflated XML file.


View inflate (int resource, ViewGroup root, boolean attachToRoot)

The root View of the inflated hierarchy. If root was supplied and attachToRoot is true, this is root; otherwise it is the root of the inflated XML file.


例如:

View view = View.inflate(this, resoutceId, mContainer);

如果傳入root不爲空,

那麼此時view表示mContainer和新創建出來的對象結合後的root View,這裏就是父容器mContainer。

當你需要對每個新創建的View對象進行操作時,如統一點擊事件等,則不能傳入父容器。


View view = View.inflate(this,resoutceId, null);

mContainer.addView(view);

如果傳入root爲空

那麼此時view表示新創建出來的View對象,就是resoutceId指定的佈局的根元素。

例如:resoutceId根元素是TextView,則view是TextView對象


另外:

LayoutInflater.from(this).inflate(resoutceId, mContainer));

//默認attach到mContainer,返回mContainer


LayoutInflater.from(this).inflate(resoutceId, mContainer, true));

//attach到mContainer,返回mContainer


LayoutInflater.from(this).inflate(resoutceId, mContainer, false)); 

//沒有attach到mContainer,返回resoutceId的根元素


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章