android layout方法_Android面试题

Android (4) 2024-09-06 12:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
android layout方法_Android面试题,希望能够帮助你!!!。

在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 layout方法_Android面试题_https://bianchenghao6.com/blog_Android_第1张

log:

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

单击有根挂载

android layout方法_Android面试题_https://bianchenghao6.com/blog_Android_第2张

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@a8

单击没有根不挂载

android layout方法_Android面试题_https://bianchenghao6.com/blog_Android_第3张

log:

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

单击没有根挂载

android layout方法_Android面试题_https://bianchenghao6.com/blog_Android_第4张

log:

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

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复