之前用RecyclerView为了达到自己想要的结果,把item的根布局(最外层Layout)的大小设为match_parent,一开始却发现一个很大的问题!咦?为什么我的item一加载就成了wrap_content的效果?我的match_parent为什么效果显示不出来…在尝试了很多很多方法觉得应该不是我写错了之后,我才意识到我根本不知道LayoutInflater的inflate这个函数的参数的意义,查了api还是不解,这个第三个参数attachToRoot到底是啥意思?为了弄懂这个问题,看了很多博客,觉得这个是个好问题!弄懂了它,你再也不会错误的用inflate了!
我们最常用的便是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)
而我们最常用的用法就是这样(RecyclerView的Adapter中):
- @Override
- public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = mInflater.inflate(R.layout.item_agenda_detail, null);
- AgendaDetailHolder holder = new AgendaDetailHolder(view);
- return holder;
- }
看似很简单的一个调用,原来有四个重载,而我们最简单的用法就是上面这段用法,也是我一开始的用法(复制粘贴就是这样,你也不会去看细节)
可当你运行测试的时候,你惊讶的发现,说好的效果呢?
下面是我item的布局文件,清清楚楚的写着match_parent
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="50dp">
- </View>
- <LinearLayout
- android:orientation="vertical"
- android:id="@+id/id_agenda_detail_layout"
- android:background="#afbfff"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
- <LinearLayout
- android:background="#FFFFFF"
- android:orientation="vertical"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
- android:layout_marginTop="2dp"
- android:layout_marginBottom="2dp"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/id_text_view_agenda_title"
- android:gravity="center"
- android:textSize="30sp"
- android:text="议程标题"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
- <TextView
- android:id="@+id/id_text_view_agenda_speaker"
- android:gravity="center"
- android:textSize="20sp"
- android:text="主讲人:"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
- <TextView
- android:id="@+id/id_text_view_agenda_time"
- android:gravity="center"
- android:textSize="20sp"
- android:text="议程时长:5:00"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
-
- <Button
- android:id="@+id/id_btn_show_agenda_file"
- android:text="查看文件"
- android:layout_centerInParent="true"
- android:layout_width="100dp"
- android:layout_height="50dp" />
-
- </RelativeLayout>
-
- </LinearLayout>
- </LinearLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="50dp">
- </View>
-
- </LinearLayout>
运行的效果我就不说了…挤在一起的item,丑陋不堪,完全和我预想的效果不一样!然后我试了一下wrap_content,我惊讶的发现,真的一模一样……所以说我的match_parent竟然被改成了wrap_content!
网上查了一圈,我发现我的adapter代码和别人的不一样!于是,我机智地改成了这样:
- @Override
- public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = mInflater.inflate(R.layout.item_agenda_detail, parent, false);
- AgendaDetailHolder holder = new AgendaDetailHolder(view);
- return holder;
- }
运行了一遍之后,我发现竟然可以了!我的效果又设置成功了,match_parent又有了效果!
但我强烈地想知道,到底为什么有了效果…所以我开始了查找资料的过程,源码中是这么写的
- public View inflate(int resource, ViewGroup root) {
- return inflate(resource, root, root != null);
- }
- public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
- if (DEBUG) System.out.println("INFLATING from resource: " + resource);
- XmlResourceParser parser = getContext().getResources().getLayout(resource);
- try {
- return inflate(parser, root, attachToRoot);
- } finally {
- parser.close();
- }
- }
这是前两种的调用,它们最终都会调用第四个重载,所以我们关注这个即可
- public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
- synchronized (mConstructorArgs) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
-
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- Context lastContext = (Context)mConstructorArgs[0];
- 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 (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, attrs, false);
- } else {
-
- View temp;
- if (TAG_1995.equals(name)) {
- temp = new BlinkLayout(mContext, attrs);
- } else {
- temp = createViewFromTag(root, name, attrs);
- }
-
- ViewGroup.LayoutParams params = null;
-
- if (root != null) {
- if (DEBUG) {
- System.out.println("Creating params from root: " +
- root);
- }
-
- params = root.generateLayoutParams(attrs);
- if (!attachToRoot) {
-
-
- temp.setLayoutParams(params);
- }
- }
-
- if (DEBUG) {
- System.out.println("-----> start inflating children");
- }
-
- rInflate(parser, temp, attrs, true);
- if (DEBUG) {
- System.out.println("-----> done inflating children");
- }
-
-
-
- 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;
- } finally {
-
- mConstructorArgs[0] = lastContext;
- mConstructorArgs[1] = null;
- }
-
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-
- return result;
- }
- }
代码很长,关键是这一段
- ViewGroup.LayoutParams params = null;
-
- if (root != null) {
- if (DEBUG) {
- System.out.println("Creating params from root: " +
- root);
- }
-
- params = root.generateLayoutParams(attrs);
- if (!attachToRoot) {
-
-
- temp.setLayoutParams(params);
- }
- }
我们的root终于出现了,意思就是当root不是空的时候,并且你的attachToRoot位false,就把root的参数设置给temp,那root的实参parent是啥呢?在这个
- <pre name="code" class="java">public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType)
函数中,parent就是RecyclerView,即你item的父试图,你创建的布局的即我们设置的layout的参数的计算都要依赖于这个父视图,而没有这个父视图(null)等于告诉框架你不需要父视图去添加你的view
那这个temp是干嘛的,我们接着看代码
-
-
- if (root == null || !attachToRoot) {
- result = temp;
- }
而这个result最终就是我们的返回结果,那我们的参数就成功的得到了计算(因为有了父视图,match_parent被计算了大小,就是你父视图,即你的RecyclerView的大小),那我想要的效果就得到设置!
通过这一行行的解释,我们终于弄明白了!root的作用就是来计算我们item的设置参数,没有root自然也没办法计算参数,那我们设置什么都不会有效果!可能我的理解会有一点偏差,不过起码也算知道了我们的设置为什么没有用的原因,后几篇文章我想对LayoutInflater做一个根本的解析,真正理解这个大师的原理。