为了达到预期的结果,利用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做一个基本的分析,真正理解这位大师的原理。