android之LayoutInflate的原理及用法

android之LayoutInflate的原理及用法在Android中用于加载一个布局的方式是通过LayoutInflater对象去加载的。那么我们如何得到这个对象呢?方式有以下2个方式:1.通过

欢迎大家来到IT世界,在知识的湖畔探索吧!

Android中用于加载一个布局的方式是通过LayoutInflater对象去加载的。那么我们如何得到这个对象呢?

方式有以下2个方式:

1.通过context得到:

LayoutInflater mLayoutInflater=getSystemService(Context.LAYOUT_INFLATER_SERVICE);

2.通过LayoutInflater的静态方式

LayoutInflater mLayoutInflater = LayoutInflater.from(context);

但是其静态方式的内部实现也是通过第一种方式得到的,源码如下:

/**

* Obtains the LayoutInflater from the given context.

*/

public static LayoutInflater from(Context context) {

LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

if (LayoutInflater == null) {

throw new AssertionError(“LayoutInflater not found.”);

}

return LayoutInflater;

}

在得到了LayoutInflater以后,我们就可能用其API进行加载我们的布局资源:

相关的API是: publicView inflate(@LayoutRes intresource, @Nullable ViewGroup root)

publicView inflate(@LayoutRes intresource, @Nullable ViewGroup root, booleanattachToRoot)

其参数说明:

resource:布局资源的ID ID for an XML layout resource to load()

root :在生成的布局体系中可选的父视图Optional view to be the parent of the generated hierarchy

attachToRoot:是否加载到父视图中。如果false,父视图创建正确的布局参数。Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the

correct subclass of LayoutParams for the root view in the XML.

在第一个API中内部会调用每二个API:

publicView inflate(@LayoutRes intresource, @Nullable ViewGroup root) {

returninflate(resource, root, root != null);

}

下面是我们分析的加载布局的函数:

publicView inflate(@LayoutRes intresource, @Nullable ViewGroup root, booleanattachToRoot) {

finalResources res = getContext().getResources();

finalXmlResourceParser parser = res.getLayout(resource);

try{

returninflate(parser, root, attachToRoot);

} finally{

parser.close();

}

}

我删除了在源码中Debug的信息

我们看一下实际加载的过程是在inflate(parser, root, attachToRoot):

publicView inflate(XmlPullParser parser, @Nullable ViewGroup root, booleanattachToRoot) {

synchronized(mConstructorArgs) {

finalContext inflaterContext =mContext;

finalAttributeSet attrs = Xml.asAttributeSet(parser);

Context lastContext = (Context) mConstructorArgs[0];

mConstructorArgs[0] = inflaterContext;

View result = root;

try{

// Look for the root node.

inttype;

while((type = parser.next()) != XmlPullParser.START_TAG&&

type != XmlPullParser.END_DOCUMENT) {

// Empty

}

if(type != XmlPullParser.START_TAG) {

throw newInflateException(parser.getPositionDescription()+“: No start tag found!”);

}

finalString name = parser.getName();

if(TAG_MERGE.equals(name)) {

if(root == null|| !attachToRoot) {

throw newInflateException(“<merge /> can be used only with a valid “

+ “ViewGroup root and attachToRoot=true”);

}

rInflate(parser, root, inflaterContext, attrs, false);

} else{

// Temp is the root view that was found in the xml

finalView temp = createViewFromTag(root, name, inflaterContext, attrs);

ViewGroup.LayoutParams params = null;

// Create layout params that match root, if supplied

params = root.generateLayoutParams(attrs);

if(!attachToRoot) {

// Set the layout params for temp if we are not

// attaching. (If we are, we use addView, below)

temp.setLayoutParams(params);

}

}

// Inflate all children under temp against its context.

rInflateChildren(parser, temp, attrs, true);

// We are supposed to attach all the views we found (int temp)

// to root. Do that now.

if(root != null&& attachToRoot) {

root.addView(temp, params);

}

// Decide whether to return the root that was passed in or the

// top view found in xml.

if(root == null|| !attachToRoot) {

result = temp;

}

}

} catch(XmlPullParserException e) {

InflateException ex = newInflateException(e.getMessage());

ex.initCause(e);

throwex;

} catch(Exception e) {

InflateException ex = newInflateException(

parser.getPositionDescription()

+ “: “+ e.getMessage());

ex.initCause(e);

throwex;

} finally{

// Don’t retain static reference on context.

mConstructorArgs[0] = lastContext;

mConstructorArgs[1] = null;

}

returnresult;

}

}

上面代码,会通过一个while定位到xml的文件的开始节点位置,得到节点的名字,如果节点的名字不TAG_MERGE,这是会创建一个临时View

finalView temp = createViewFromTag(root, name, inflaterContext, attrs);

如果root不是 null,会生成布局参数,如果不挂载会设置其布局参数到这个临时的View上。

params = root.generateLayoutParams(attrs);

if(!attachToRoot) {

// Set the layout params for temp if we are not

// attaching. (If we are, we use addView, below)

temp.setLayoutParams(params);

}

加载在这个临时view下所有的孩子,

// Inflate all children under temp against its context.

rInflateChildren(parser, temp, attrs, true);

//如果root不是null并且attach,将这个临时view加载到这个root

if(root != null&& attachToRoot) {

root.addView(temp, params);

}

// Decide whether to return the root that was passed in or the

// top view found in xml.

if(root == null|| !attachToRoot) {

result = temp;

}

返回生成的布局体系。

总结:

root attachToRoot 返回的View

null true 返回相应的View没有布局参数

null false 返回相应的View没有布局参数

not null true 返回root,并将在xml的所有布局生成,且添加到root上

not null false 返回相应的在xml生成的指定的布局参数的View

例子如下:

布局资源inflater_button_dimens:

<?xml version=“1.0”encoding=“utf-8”?>

<Buttonxmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“100dp”

android:layout_height=“100dp”

android:text=“100dp”

tools:text=“100dp”

/>

activity_layout_inflater:

<?xml version=“1.0”encoding=“utf-8”?>

<LinearLayout

xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:orientation=“vertical”>

<Button

android:layout_width=“match_parent”

android:text=有根不挂载

android:onClick=“inflaterButtonWithRootNoAttach”

android:layout_height=“wrap_content”/>

<Button

android:layout_width=“match_parent”

android:text=有根挂载

android:onClick=“inflaterButtonWithRootAttach”

android:layout_height=“wrap_content”/>

<Button

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:text=没有根不挂载

android:onClick=“inflaterButtonWithoutRootNoAttach”

/>

<Button

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:text=没有根挂载

android:onClick=“inflaterButtonWithoutRootAttach”

/>

<LinearLayout

android:id=“@+id/inflater_container”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:orientation=“vertical”

/>

</LinearLayout>

Activity的源码:

public classLayoutInflaterActivity extendsAppCompatActivity {

private static finalString TAG= “LayoutInflaterActivity”;

privateLinearLayout mInflaterContainer;

privateLayoutInflater mLayoutInflater;

@Override

protected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_layout_inflater);

mInflaterContainer= (LinearLayout) findViewById(R.id.inflater_container);

initData();

}

private voidinitData() {

mLayoutInflater= (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}

public voidinflaterButtonWithRootNoAttach(View view) {

removeContainerAllChild();

Button button = (Button) mLayoutInflater.inflate(R.layout.inflater_button_dimens, mInflaterContainer, false);

button.setText(有根不挂载);

if(button.getLayoutParams() != null) {

Log.d(TAG, button.getLayoutParams().width+“—“+button.getLayoutParams().height);

}

mInflaterContainer.addView(button);

}

public voidinflaterButtonWithRootAttach(View view) {

removeContainerAllChild();

View tem = mLayoutInflater.inflate(R.layout.inflater_button_dimens, mInflaterContainer, true);

Log.d(TAG,“mInflaterContainer==tem:”+(mInflaterContainer==tem));

intchildCount = mInflaterContainer.getChildCount();

if(childCount <= 0) {

return;

}

Button btn = (Button) mInflaterContainer.getChildAt(0);

btn.setText(有根挂载);

for(intchildIndex = 0; childIndex < childCount; childIndex++) {

Log.d(TAG, “childIndex:”+ childIndex + ” “+ mInflaterContainer.getChildAt(childIndex).toString());

Log.d(TAG,“childIndex:”+childIndex+” “+mInflaterContainer.getChildAt(childIndex).getLayoutParams().toString());

}

}

public voidinflaterButtonWithoutRootNoAttach(View view) {

removeContainerAllChild();

Button button = (Button) mLayoutInflater.inflate(R.layout.inflater_button_dimens, null, false);

button.setText(没有根不挂载);

if(button.getLayoutParams() != null) {

Log.d(TAG, button.getLayoutParams().width+“—“+button.getLayoutParams().height);

} else{

Log.d(TAG, “null layoutParameter”);

}

mInflaterContainer.addView(button);

}

public voidinflaterButtonWithoutRootAttach(View view) {

removeContainerAllChild();

Button button = (Button) mLayoutInflater.inflate(R.layout.inflater_button_dimens, null, true);

button.setText(没有根挂载);

if(button.getLayoutParams() != null) {

Log.d(TAG, button.getLayoutParams().width+“—“+button.getLayoutParams().height);

}else{

Log.d(TAG, “null layoutParameter”);

}

mInflaterContainer.addView(button);

}

public voidremoveContainerAllChild() {

mInflaterContainer.removeAllViews();

}

}

单击有根不挂载:

android之LayoutInflate的原理及用法

log:

04-07 14:13:50.928 25995-25995/com.lxn.job D/LayoutInflaterActivity: 150—150

单击有根挂载

android之LayoutInflate的原理及用法

Log:

04-07 14:16:41.172 25995-25995/com.lxn.job D/LayoutInflaterActivity: mInflaterContainer==tem:true

04-07 14:16:41.172 25995-25995/com.lxn.job D/LayoutInflaterActivity: childIndex:0 android.support.v7.widget.AppCompatButton@53591f00

04-07 14:16:41.172 25995-25995/com.lxn.job D/LayoutInflaterActivity: childIndex:0 android.widget.LinearLayout$LayoutParams@535922a8

单击没有根不挂载

android之LayoutInflate的原理及用法

log:

04-07 14:18:17.184 25995-25995/com.lxn.job D/LayoutInflaterActivity: null layoutParameter

单击没有根挂载

android之LayoutInflate的原理及用法

log:

04-07 14:19:25.972 25995-25995/com.lxn.job D/LayoutInflaterActivity: null layoutParameter

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/48728.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信