(Android开发)LayoutInflater.inflate()参数详解

来源:互联网 发布:linux oracle监听配置 编辑:程序博客网 时间:2024/05/02 16:22

转载请注明出处:http://blog.csdn.net/ljr900723/article/details/40187655


inflate函数是Android开发中常用的一个函数,但是很多朋友对它参数的意义不太了解,我在网上翻阅了一些资料后,有了自己的想法,在这里和大家分享一下。

这里只讨论inflate(int resource, ViewGroup root, boolean attachToRoot)这个形式的函数,理解了这个函数,其他参数形式的重载便很容易理解了。这个函数接收3个参数,resource参数想必大家都能明白,这里只讨论root和attachToRoot两个参数。

如果有朋友对inflate还比较陌生,可以先参考郭大侠的这篇文章:http://blog.csdn.net/guolin_blog/article/details/12921889

下面进入正题,不管你是使用的哪个inflate()方法的重载,最终都会辗转调用到LayoutInflater的如下代码中:

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    synchronized (mConstructorArgs) {        final AttributeSet attrs = Xml.asAttributeSet(parser);        mConstructorArgs[0] = mContext;        View result = root;        try {            int type;            while ((type = parser.next()) != XmlPullParser.START_TAG &&                    type != XmlPullParser.END_DOCUMENT) {            }            if (type != XmlPullParser.START_TAG) {                throw new InflateException(parser.getPositionDescription()                        + ": No start tag found!");            }            final String name = parser.getName();            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, attrs);            } else {                View temp = createViewFromTag(name, attrs);                ViewGroup.LayoutParams params = null;                if (root != null) {                    params = root.generateLayoutParams(attrs);                    if (!attachToRoot) {                        temp.setLayoutParams(params);                    }                }                rInflate(parser, temp, attrs);                if (root != null && attachToRoot) {                    root.addView(temp, params);                }                if (root == null || !attachToRoot) {                    result = temp;                }            }        } catch (XmlPullParserException e) {            InflateException ex = new InflateException(e.getMessage());            ex.initCause(e);            throw ex;        } catch (IOException e) {            InflateException ex = new InflateException(                    parser.getPositionDescription()                    + ": " + e.getMessage());            ex.initCause(e);            throw ex;        }        return result;    }}

下面我们分别讨论root和attachToRoot两个参数的取值情况:

①root == null 

先看上述函数的如下代码片段:

if (root == null || !attachToRoot) {    result = temp;}

如果root参数为空指针,则attachToRoot参数没有意义,我们不指定该布局的根布局,并且返回resource参数指定布局文件最外层布局的View


②root != null && attachToRoot == TRUE

先看上述函数的如下代码片段:

if (root != null && attachToRoot) {    root.addView(temp, params);}
显然,我们将temp布局作为root的子View添加到了root所指向的根布局中,并且返回值是root所指向的View而不是resource参数指定布局文件最外层布局的View


③root != null && attachToRoot == FALSE

这是最难理解的一种情况,也是很多朋友理解错误的一种情况,同理先看上述函数的如下代码片段:

View temp = createViewFromTag(name, attrs);ViewGroup.LayoutParams params = null;if (root != null) {    params = root.generateLayoutParams(attrs);    if (!attachToRoot) {        temp.setLayoutParams(params);    }}
如果出现了这种情况,我们执行了temp.setLayoutParams(params),参数params是从root中提取的,说明我们把root所指向的View“看作是”resource参数指定布局文件最外层布局的View的根布局来设置它的布局参数。这里的“看作是”理解为只用来设置布局参数而这两个布局并没有父子关系。再直白一点就是“只借你的布局参数一用,我们并无再多的关系”。这里如果理解为attachToRoot为FALSE则root参数无效,我觉得是不正确的。

为了更有说服力,我为这种情况做了测试,首先创建一个Activity,代码如下:

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);LinearLayout mainLayout = (LinearLayout)findViewById(R.id.main_layout);View testButton1 = LayoutInflater.from(this).inflate(R.layout.layout_button, null, false);mainLayout.addView(testButton1);View testButton2 = LayoutInflater.from(this).inflate(R.layout.layout_button, mainLayout, false);mainLayout.addView(testButton2);}}

另外,为testButton创建了layout_button.xml的布局文件,如下:

<Button xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="300dp"    android:layout_height="100dp"    android:text="Button" ></Button>
最后是activity的布局文件main_activity.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/main_layout"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"></LinearLayout>
最后测试结果如下图:


显然,两个Button都是从同一个布局文件加载而来,但是显示的大小却不一样。第一个Button的root参数为null,因为它自己就是最外层布局,因此在xml文件中定义的“layout_width”和“layout_height”都起不到作用(如果不能理解,可以先阅读关于View绘制流程的文章)。实际这里第一个Button的宽和高刚好是放下“Button”文本的大小。后第二个Button我们传递的root参数不为null,因此在绘制第二个Button时,借助了root所指向View(这里是主布局)的布局参数,因此“300dp”和“100dp”才在屏幕中显示出来了。这完全印证了我前面的论述。

最后,总结一下:
①root == null(attachToRoot参数无效):加载resource参数指向布局文件的布局给View,返回值是这个View;
②root != null && attachToRoot == TRUE:加载resource参数指向布局文件的布局给View,并且该View作为root参数所指向View的子View,返回值是root指向的View
③root != null && attachToRoot == FALSE:加载resource参数指向布局文件的布局给View,并且借助root指向的View的布局参数来布局,返回值是这个View


好了,这篇文章就写到这里了,第一次写文章,不足之处请多包涵。也希望感兴趣的朋友一起讨论。





0 0
原创粉丝点击