RecyclerView控件列表项布局match_parent属性失效的根本原理

发布时间:2023-05-09 09:55:39

为了达到预期的结果,利用Recyclerview将item的根布局(最外层Layout)设置为match_parent,一开始,我发现了一个大问题!咦?为什么我的item一加载就成为wrap_content的效果?为什么我的match_parent的效果不能显示...在尝试了很多方法,觉得应该不是我写错了,才意识到根本不知道layoutinflaterinflate函数的参数的意义。查了api还是不明白这个第三个参数attachtorot是什么意思?为了理解这个问题,我读了很多博客,认为这是个好问题!了解了它,你再也不会用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):

[java] view plain copy

1. @Override  2. public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {  3. null);  4. new AgendaDetailHolder(view);  5. return holder;  6.     }

这似乎是一个非常简单的呼叫。原来有四个重载,我们最简单的用法是上述用法,这也是我最初的用法(复制粘贴就是这样,你不会看细节)

但是当你运行测试时,你会惊讶地发现,好的效果呢?

以下是我的item布局文件,清楚地写着match_parent

[html] view plain copy

1. <?xml version="1.0" encoding="utf-8"?>  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  3. android:orientation="vertical"  4. android:layout_width="match_parent"  5. android:layout_height="match_parent">  6.   7. <View  8. android:layout_width="match_parent"  9. android:layout_height="50dp">  10. </View>  11. <LinearLayout  12. android:orientation="vertical"  13. android:id="@+id/id_agenda_detail_layout"  14. android:background="#afbfff"  15. android:layout_width="match_parent"  16. android:layout_height="0dp"  17. android:layout_weight="1">  18. <LinearLayout  19. android:background="#FFFFFF"  20. android:orientation="vertical"  21. android:layout_marginLeft="2dp"  22. android:layout_marginRight="2dp"  23. android:layout_marginTop="2dp"  24. android:layout_marginBottom="2dp"  25. android:layout_width="match_parent"  26. android:layout_height="match_parent">  27.   28. <TextView  29. android:id="@+id/id_text_view_agenda_title"  30. android:gravity="center"  31. android:textSize="30sp"  32. android:text=“议程标题”  33. android:layout_width="match_parent"  34. android:layout_height="0dp"  35. android:layout_weight="1"/>  36. <TextView  37. android:id="@+id/id_text_view_agenda_speaker"  38. android:gravity="center"  39. android:textSize="20sp"  40. android:text=“主讲人:”  41. android:layout_width="match_parent"  42. android:layout_height="0dp"  43. android:layout_weight="1"/>  44. <TextView  45. android:id="@+id/id_text_view_agenda_time"  46. android:gravity="center"  47. android:textSize="20sp"  48. android:text=议程时长:5:00"  49. android:layout_width="match_parent"  50. android:layout_height="0dp"  51. android:layout_weight="1"/>  52. <RelativeLayout  53. android:layout_width="match_parent"  54. android:layout_height="0dp"  55. android:layout_weight="1">  56.   57. <Button  58. android:id="@+id/id_btn_show_agenda_file"  59. android:text=“查看文件”  60. android:layout_centerInParent="true"  61. android:layout_width="100dp"  62. android:layout_height="50dp" />  63.   64. </RelativeLayout>  65.   66. </LinearLayout>  67. </LinearLayout>  68. <View  69. android:layout_width="match_parent"  70. android:layout_height="50dp">  71. </View>  72.   73. </LinearLayout>

我就不说操作效果了...挤在一起的item很丑,和我预期的效果完全不一样!然后我试了wrap_content,我惊讶地发现,真的一模一样...所以我的match_parent被改成了wrap_content!

我在网上查了一圈,发现我的adapter代码和别人不一样!于是,我机智地改成了这样:

[java] view plain copy

1. @Override  2. public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {  3. false);  4. new AgendaDetailHolder(view);  5. return holder;  6.     }

经过一次操作,我发现没关系!我的效果又设定成功了,match_parent又有效果了!

但是我强烈想知道为什么会有效果...于是我开始了搜索数据的过程,源代码是这样写的。

[java] view plain copy

1. public View inflate(int resource, ViewGroup root) {    2. return inflate(resource, root, root != null);    3. }

[java] view plain copy

1. public View inflate(int resource, ViewGroup root, boolean attachToRoot) {    2. if (DEBUG) System.out.println("INFLATING from resource: " + resource);    3.     XmlResourceParser parser = getContext().getResources().getLayout(resource);    4. try {    5. return inflate(parser, root, attachToRoot);    6. finally {    7.         parser.close();    8.     }    9. }

这是前两种调用,它们最终会调用第四个重载,所以我们可以注意这一点

[java] view plain copy

1. public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {  2. synchronized (mConstructorArgs) {  3. "inflate");  4.    5. final AttributeSet attrs = Xml.asAttributeSet(parser);  6. 0];  7. 0] = mContext;  8.             View result = root;  9.    10. try {  11. // Look for the root node.  12. int type;  13. while ((type = parser.next()) != XmlPullParser.START_TAG &&  14.                         type != XmlPullParser.END_DOCUMENT) {  15. // Empty  16.                 }  17.    18. if (type != XmlPullParser.START_TAG) {  19. throw new InflateException(parser.getPositionDescription()  20. ": No start tag found!");  21.                 }  22.    23. final String name = parser.getName();  24.                    25. if (DEBUG) {  26. ***************************;  27. "Creating root view: "  28.                             + name);  29. ***************************;  30.                 }  31.    32. if (TAG_MERGE.equals(name)) {  33. if (root == null || !attachToRoot) {  34. throw new InflateException("<merge> can be used only with a valid "  35. "ViewGroup root and attachToRoot=true");  36.                     }  37.    38. false);  39. else {  40. // Temp is the root view that was found in the xml  41.                     View temp;  42. if (TAG_1995.equals(name)) {  43. new BlinkLayout(mContext, attrs);  44. else {  45.                         temp = createViewFromTag(root, name, attrs);  46.                     }  47.    48. null;  49.    50. if (root != null) {  51. if (DEBUG) {  52. "Creating params from root: " +  53.                                     root);  54.                         }  55. // Create layout params that match root, if supplied  56.                         params = root.generateLayoutParams(attrs);  57. if (!attachToRoot) {  58. // Set the layout params for temp if we are not  59. // attaching. (If we are, we use addView, below)  60.                             temp.setLayoutParams(params);  61.                         }  62.                     }  63.    64. if (DEBUG) {  65. "-----> start inflating children");  66.                     }  67. // Inflate all children under temp  68. true);  69. if (DEBUG) {  70. "-----> done inflating children");  71.                     }  72.    73. // We are supposed to attach all the views we found (int temp)  74. // to root. Do that now.  75. if (root != null && attachToRoot) {  76.                         root.addView(temp, params);  77.                     }  78.    79. // Decide whether to return the root that was passed in or the  80. // top view found in xml.  81. if (root == null || !attachToRoot) {  82.                         result = temp;  83.                     }  84.                 }  85.    86. catch (XmlPullParserException e) {  87. new InflateException(e.getMessage());  88.                 ex.initCause(e);  89. throw ex;  90. catch (IOException e) {  91. new InflateException(  92.                         parser.getPositionDescription()  93. ": " + e.getMessage());  94.                 ex.initCause(e);  95. throw ex;  96. finally {  97. // Don't retain static reference on context.  98. 0] = lastContext;  99. 1] = null;  100.             }  101.    102.             Trace.traceEnd(Trace.TRACE_TAG_VIEW);  103.    104. return result;  105.         }  106.     }

代码很长,关键是这一段

[java] view plain copy

1. ViewGroup.LayoutParams params = null;    2.     3. if (root != null) {    4. if (DEBUG) {    5. "Creating params from root: " +    6.                 root);    7.     }    8. // Create layout params that match root, if supplied    9.     params = root.generateLayoutParams(attrs);    10. if (!attachToRoot) {    11. // Set the layout params for temp if we are not    12. // attaching. (If we are, we use addView, below)    13.         temp.setLayoutParams(params);    14.     }    15. }

我们的root终于出现了,这意味着当root不是空的时候,你的attachtorot位置false将root的参数设置为temp。root的实际参与parent是什么?在这里

[java] view plain copy

1. <pre name="code" class="java">public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType)

在函数中,parent是recyclerview,即你item的父亲试图,你创建的布局是我们设置的layout参数的计算取决于这个父视图,而不是这个父视图(null)这意味着告诉框架你不需要父视图添加你的view

这个temp是干什么的?让我们看看代码

[java] view plain copy

1. // Decide whether to return the root that was passed in or the  2. // top view found in xml.  3. if (root == null || !attachToRoot) {  4.                         result = temp;  5.                     }

而这个result最终是我们的返回结果,那么我们的参数就成功地计算出来了(因为有了父视图,match_parent的大小是你父亲的视图,也就是你的Recyclerview的大小),所以我想要的效果是设置的!

通过对这一行的解释,我们终于明白了!root的功能是计算我们item的设置参数。没有root,我们自然无法计算参数。那么我们设置的任何东西都不会有效果!也许我的理解会有一点偏差,但至少我知道为什么我们的设置没有用。最后几篇文章文章我想对Layoutinflater做一个基本的分析,真正理解这位大师的原理。

上一篇 开源开发者提交不安全代码,遭 Linus 炮轰
下一篇 补间动画,属性动画实现购物车添加动画

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题