inflater.inflate()参数详解

前言

今天在lint项目的代码时,又遇到了inflate方法的参数问题,之前看过相关的文章,又没有记录下来,导致时间长了就忘记了。今天再次遇到这个问题,便老老实实记录一下LayouInflater中inflate方法两个参数和三个参数的区别。

用法

LayoutInflater.from(RecylerActivity.this).inflate(R.layout.my_text_view,viewGroup,false);

View.inflate(RecylerActivity.this, R.layout.my_text_view, null);

通过看源码得知View.inflate()方法实际上调用的也是LayoutInflater.from(int resource, ViewGroup root, boolean attachToRoo);

区别

我们最常用的便是LayoutInflater的inflate方法,这个方法重载了四种调用方式,分别为:

1. public View inflate(int resource, ViewGroup root)

2. public View inflate(int resource, ViewGroup root, boolean attachToRoot)

3. public View inflate(XmlPullParser parser, ViewGroup root)

4. public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)

这四种使用方式中,我们最常用的是第一种方式,inflate方法的主要作用就是将xml转换成一个View对象,用于动态的创建布局。虽然重载了四个方法,但是这四种方法最终调用的,还是第四种方式。第四种方式也很好理解,内部实现原理就是利用Pull解析器,对Xml文件进行解析,然后返回View对象。

inflate方法有三个参数,分别是 
1.resource 布局的资源id

2.root 填充的根视图

3.attachToRoot 是否将载入的视图绑定到根视图中

我们经常使用的第一种形式为例,你在重写BaseAdapter的getView方法的时候是否这样做过

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = inflate(R.layout.item_row, null);
    }
    return convertView;
}

我们将root参数设为空,功能确实实现了,但是这里还隐藏着一个隐患,这种方式并不是inflate正确的使用姿势,下面我们通过一个Demo,来说一下这样使用造成的弊端。 
对应的布局文件如下

<!--?xml version="1.0" encoding="utf-8"?-->
    <linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@android:color/holo_orange_light"
        android:gravity="center"
        android:orientation="vertical">

        <textview
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="11"
            android:textcolor="@android:color/black"
            android:textsize="22sp">

        </textview>
    </linearlayout>

OneActivity的代码如下

public class OneActivity extends Activity {

    private ListView list1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);
        list1 = (ListView) findViewById(R.id.list1);
        list1.setAdapter(new MyAdapter(this));
    }

    private class MyAdapter extends BaseAdapter {

        private LayoutInflater inflater;

        MyAdapter(Context context) {
            inflater = LayoutInflater.from(context);
        }

        @Override
        public int getCount() {
            return 20;
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.item_list, null);
            }
            TextView tv = (TextView) convertView.findViewById(R.id.tv);
            tv.setText(position+"");
            return convertView;
        }

    }

}
  •  

TwoActivity的代码如下

public class TwoActivity extends Activity {
    private ListView list2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);
        list2 = (ListView) findViewById(R.id.list2);
        list2.setAdapter(new MyAdapter(this));
    }

    private class MyAdapter extends BaseAdapter {

        private LayoutInflater inflater;

        MyAdapter(Context context) {
            inflater = LayoutInflater.from(context);
        }

        @Override
        public int getCount() {
            return 20;
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.item_list, parent,false);
            }
            TextView tv = (TextView) convertView.findViewById(R.id.tv);
            tv.setText(position + "");
            return convertView;
        }

    }

}

两个文件最关键的区别就一句话, 
在getView方法中,OneActivity是 
convertView = inflater.inflate(R.layout.item_list, null); 
在getView方法中,TwoActivity是 
convertView = inflater.inflate(R.layout.item_list, parent,false);

我们先看一下显示效果,再说两者的区别 
OneActivity效果 
这里写图片描述

TwoActivity的显示效果 
这里写图片描述

我们可以很明显的看出来,使用第一种方式,根布局的高度设置60dp没有起作用,系统还是按照包裹内容的方式加载的,为什么会产生这种效果呢?我们从需要inflate方法的源代码中找一下答案。

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
        return inflate(resource, root, root != null);
    }
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                    + Integer.toHexString(resource) + ")");
        }

        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {
                // Look for the root node.
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }

                if (type != XmlPullParser.START_TAG) {
                    throw new InflateException(parser.getPositionDescription()
                            + ": No start tag found!");
                }

                final String name = parser.getName();

                if (DEBUG) {
                    System.out.println("**************************");
                    System.out.println("Creating root view: "
                            + name);
                    System.out.println("**************************");
                }

                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);
                } else {
                    // Temp is the root view that was found in the xml
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // 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);
                        }
                    }

                    if (DEBUG) {
                        System.out.println("-----> start inflating children");
                    }

                    // Inflate all children under temp against its context.
                    rInflateChildren(parser, temp, attrs, true);

                    if (DEBUG) {
                        System.out.println("-----> done inflating children");
                    }

                    // 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) {
                final InflateException ie = new InflateException(e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } catch (Exception e) {
                final InflateException ie = new InflateException(parser.getPositionDescription()
                        + ": " + e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } finally {
                // Don't retain static reference on context.
                mConstructorArgs[0] = lastContext;
                mConstructorArgs[1] = null;

                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }

            return result;
        }
    }

重点关注下面的

        final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // 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);
                        }
                    }

这些代码的意思就是,当我们传进来的root参数不是空的时候,并且attachToRoot是false的时候,也就是上面的TwoActivity的实现方式的时候,会给temp设置一个LayoutParams参数。

// 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;
                    }

当我们传进来的root不是null,并且第三个参数是false的时候,这个temp就被加入到了root中,并且把root当作最终的返回值返回了。而当我们设置root为空的时候,没有设置LayoutParams参数的temp对象,作为返回值返回了。

因此,我们可以得出下面的结论: 
1.若我们采用convertView = inflater.inflate(R.layout.item_list, null);方式填充视图,item布局中的根视图的layout_XX属性会被忽略掉,然后设置成默认的包裹内容方式 
2.如果我们想保证item的视图中的参数不被改变,我们需要使用convertView = inflater.inflate(R.layout.item_list, parent,false);这种方式进行视图的填充 
3.除了使用这种方式,我们还可以设置item布局的根视图为包裹内容,然后设置内部控件的高度等属性,这样就不会修改显示方式了。

总之一句话,推荐用下边这种方式:

inflater.inflate(R.layout.item, parent, false);

 



另外本人还开设了个人公众号:JiandaoStudio ,会在公众号内定期发布行业信息,以及各类免费代码、书籍、大师课程资源。

 

                                            

扫码关注本人微信公众号,有惊喜奥!公众号每天定时发送精致文章!回复关键词可获得海量各类编程开发学习资料!

例如:想获得Python入门至精通学习资料,请回复关键词Python即可。

  • 25
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值