Android LayoutInflater讲解
来源:互联网 发布:gal一般用哪种编程语言 编辑:程序博客网 时间:2024/06/07 22:52
一、前言
以前用adapter的时候每次就知道copy代码,对LayoutInflater不求深入了解,真是惭愧!今天抽空把LayoutInflater的源码看了看,终于有些感悟,记录下来,希望对大家有些帮助。
二、方法介绍
我们最常用的就是以下2个方法:
1.LayoutInflater.from(MainActivity.this).inflate(int resource, ViewGroup root);2.LayoutInflater.from(MainActivity.this).inflate(int resource, ViewGroup root, boolean attachToRoot);
第1个方法的源码是这样的:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) { return inflate(resource, root, root != null); }
可以看的出来,在方法中调用的是第2中方法,这样算起来就剩下第2个方法了,使有的时候会出现这二种情况:
1、convertView = mInflater.inflate(R.layout.item, parent ,false);2、convertView = mInflater.inflate(R.layout.item, parent ,true);
可以看的出,它们的区别就在于最后一个boolean类型的参数,那它们二个有什么区别呢?我们先来看个例子
三、举个例子看现象
我们在Linearnlayout中分别添加以下三种情况的view,看看它们的显示:
inflate(layoutId, null )inflate(layoutId, root, false ) inflate(layoutId, root, true )
Activity代码
private LinearLayout contentLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contentLayout = (LinearLayout) findViewById(R.id.contentLayout);// View view1 = LayoutInflater.from(MainActivity.this).inflate(R.layout.item,null);// View view2 = LayoutInflater.from(MainActivity.this).inflate(R.layout.item,contentLayout,false);// View view3 = LayoutInflater.from(MainActivity.this).inflate(R.layout.item,contentLayout,true);// contentLayout.addView(view1);//情况1// contentLayout.addView(view2);//情况2// contentLayout.addView(view3);//情况3 }
activity_main代码:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/contentLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"></LinearLayout>
item代码:
<?xml version="1.0" encoding="utf-8"?><Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" />
显示如下:
1.inflate(layoutId, null )的情况
2.inflate(layoutId, root, false ) 的情况
3.inflate(layoutId, root, true ) 的情况
是的,要相信自己,你没看错,第3种情况确实是报错了!
由上面的效果图我想信大家一定有这几个疑问:
1.为什么情况1宽度是整个屏幕,情况2是自适应。2.为什么情况3报错了。
接下来,我们来看看源码,找出是什么导致了这些情况!
四、源码解析
上面我们分析过,这3中情况最后都调用了一个方法,我们来看看它的源码:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { .... //先将root赋值给result,后面我们会根据不同的参数改变result值,最后我们要返回resulut; View result = root; try { // Look for the root node. ... 这块是用解析xml布局代码 ... if (TAG_MERGE.equals(name)) { ... } else { // Temp is the root view that was found in the xml //在createViewFromTag()方法的内部调用createView()方法,然后使用反射的方式创建出View的实例并返回。 final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { // 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) // 当root不为null,attachToRoot为false时,为temp设置了LayoutParams. temp.setLayoutParams(params); } } // Inflate all children under temp against its context. rInflateChildren(parser, temp, attrs, true); // We are supposed to attach all the views we found (int temp) // to root. Do that now. //重点看这里,如果root不为空 并且 attachToRoot为true的时候,给temp添加LayoutParams属性 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. //重点看这里,如果root不为空 并且 attachToRoot为 false的时候,直接返回temp 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; } }
这了让大家看的简单一点,我省略了很多无用的代码,大家看源码中有汉字的地方,那是重点。
1:声明了View result = root ;//最终返回值为result
2:temp = createViewFromTag(root, name, attrs);创建了View
3:
if(root!=null) { params = root.generateLayoutParams(attrs); if (!attachToRoot) { temp.setLayoutParams(params); } }
当root不为null,attachToRoot为false时,为temp设置了LayoutParams.
4:
if (root != null && attachToRoot) { root.addView(temp, params); }
当root不为null,attachToRoot为true时,将tmp按照params添加到root中。
5.
if (root == null || !attachToRoot) { result = temp; }
如果root为null,或者attachToRoot为false则,将temp赋值给result。
最后返回result。
经上面的分析,我们可以得到以下结论:
从上面的分析已经可以看出:1.Inflate(resId , null ) 只创建temp ,返回temp2.Inflate(resId , parent, false )创建temp,然后执行temp.setLayoutParams(params);返回temp3.Inflate(resId , parent, true ) 创建temp,然后执行root.addView(temp, params);最后返回root
由此我们可以解释为什么情况3会报错:
因为root.addView(temp, params)这句话执行了,我们的contentLayout已经将button添加到里面去了,如果我们再调用contentLayout.addView(view3);它肯定会报错的。我们可以验证一下,代码如下:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contentLayout = (LinearLayout) findViewById(R.id.contentLayout); View view3 = LayoutInflater.from(MainActivity.this).inflate(R.layout.item,contentLayout,true); }
这们在这里只是调用了inflate(R.layout.item,contentLayout,true);并没有调用contentLayout.addView(view3)。看一下效果图:
看到没有,这就证实了我们上面的分析:
Inflate(resId , parent, true ) 创建temp,然后执行root.addView(temp, params);最后返回root
再在看看第2个坑:为什么情况1的宽度是整个屏幕,情况2是自适应呢?并且在情况1中不管button设置成多大的值,它的宽度都是整个屏幕。
这里我要向大家道歉,因为我也不知道为什么。对不起。在上面我们分析了:
Inflate(resId , null ) 只创建temp ,返回temp
只创建view,并没有设置LayoutParams,这才导致它的显示不正常,但为什么不正常,我还没找到原因。后面我会再找找。
五、结尾
好了就讲到这里吧,希望对大家有所帮助。
在技术上我依旧是个小渣渣,加油!勉励自己!
- Android LayoutInflater讲解
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- android layoutinflater
- Android LayoutInflater
- Android - LayoutInflater
- Android-----LayoutInflater
- Android - LayoutInflater
- Android - LayoutInflater
- AngularJS与后端php的数据交互
- 桥接模式和NAT模式区别
- Android常用实例—Alert Dialog的使用
- Java的栈与堆
- webpack和gulp区别
- Android LayoutInflater讲解
- 为Android安装BusyBox —— 完整的bash shell
- 为了解决viewpager彻底删除fragment问题
- openshift搭建registry-持久存储nfs
- Android studio自定义变量
- 实现Spring Boot、 Redis、 Shiro集群
- 简单梳理下python的一些常用代码
- 仿iOS滚轮选择控件(已在鸿洋的微信公众号上发表)
- 闪回之 Flashback Query (dml表、过程、函数、包等)、Flashback version Query