LayoutInflater 分析
来源:互联网 发布:python中syntax error 编辑:程序博客网 时间:2024/05/17 08:53
1,获取LayoutInflater 对象
public static LayoutInflater from(Context context) { LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (LayoutInflater == null) { throw new AssertionError("LayoutInflater not found."); } return LayoutInflater; }
2,LayoutInflater.inflate()方法参数
public View inflate(int resource, 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(); } }无论调用的是inflate的哪一种重载方法,最后调用的都是
inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot),
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; //定义返回值,初始化为传入的形参root View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } //如果一开始就是END_DOCUMENT,那说明xml文件有问题 if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } //有了上面判断说明这里type一定是START_TAG,也就是xml文件里的root node 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)) { //处理merge tag的情况(merge,你懂的,APP的xml性能优化) //root必须非空且attachToRoot为true,否则抛异常结束(APP使用merge时要注意的地方, //因为merge的xml并不代表某个具体的view,只是将它包起来的其他xml的内容加到某个上层 //ViewGroup中。) if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } //递归inflate方法调运 rInflate(parser, root, attrs, false, false); } else { // Temp is the root view that was found in the xml //xml文件中的root view,根据tag节点创建view对象 final View temp = createViewFromTag(root, name, attrs, false); 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 //根据root生成合适的LayoutParams实例 params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) //如果attachToRoot=false就调用view的setLayoutParams方法 temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } // Inflate all children under temp //递归inflate剩下的children rInflate(parser, temp, attrs, true, 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非空且attachToRoot=true则将xml文件的root view加到形参提供的root里 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) { //返回xml里解析的root view 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 { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); //返回参数root或xml文件里的root view return result; } }
当我们infalte布局之后会调用View类的onFinishInflate回调(和setContentView的回调
onContentChanged
类似),所以,可以看见,当我们自定义View时在构造函数inflate一个xml后可以实现onFinishInflate这个方法一些自定义的逻辑。/** * Finalize inflating a view from XML. This is called as the last phase * of inflation, after all child views have been added. * * <p>Even if the subclass overrides onFinishInflate, they should always be * sure to call the super method, so that we get called. */ protected void onFinishInflate() { }
- inflate(xmlId, null); 只创建temp的View,然后直接返回temp,xml中最外层布局的 宽高 失效。
- inflate(xmlId, parent); 创建temp的View,然后执行root.addView(temp, params);最后返回root。xml中最外层布局的 宽高 有效。
- inflate(xmlId, parent, false); 创建temp的View,然后执行temp.setLayoutParams(params);然后再返回temp。
- inflate(xmlId, parent, true); 创建temp的View,然后执行root.addView(temp, params);最后返回root。
- inflate(xmlId, null, false); 只创建temp的View,然后直接返回temp。
- inflate(xmlId, null, true); 只创建temp的View,然后直接返回temp。
我们通常在xml布局文件中,使用layout_width和layout_height来设置View的大小,但其实这不是view的真是大小,实际设置的是view在ViewGroup布局中的大小,所以
反过来看命名,是layout_width,而不是width。
但是,问题来了,我们在setContentView的时候,也是通过inflate注入布局的,那时候xml最外层的布局指定大小都是有效的啊,那是为什么呢?
因为,xml文件布局是放在id为content的Fragment中的,所以layout_width和layout_height才会生效。
3,inflate(xmlId, parent, true); 创建temp的View,然后执行root.addView(temp, params);最后返回root。layout_width和layout_height的真实含义
例子:listView中的item通过inflate的方式,注入布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/listview" android:dividerHeight="5dp" android:layout_width="match_parent" android:layout_height="match_parent"></ListView></LinearLayout>
textview_layout.xml文件:
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="100dp" android:layout_height="40dp" android:text="Text Test" android:background="#ffa0a00c"/>textview_layout_parent.xml文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout android:layout_height="wrap_content" android:layout_width="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="100dp" android:layout_height="40dp" android:text="Text Test" android:background="#ffa0a00c"/></LinearLayout>
ListView的自定义Adapter文件:
public class InflateAdapter extends BaseAdapter { private LayoutInflater mInflater = null; public InflateAdapter(Context context) { mInflater = LayoutInflater.from(context); } @Override public int getCount() { return 8; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { //说明:这里是测试inflate方法参数代码,不再考虑性能优化等TAG处理 return getXmlToView(convertView, position, parent); } private View getXmlToView(View convertView, int position, ViewGroup parent) { View[] viewList = { mInflater.inflate(R.layout.textview_layout, null),// mInflater.inflate(R.layout.textview_layout, parent), mInflater.inflate(R.layout.textview_layout, parent, false),// mInflater.inflate(R.layout.textview_layout, parent, true), mInflater.inflate(R.layout.textview_layout, null, true), mInflater.inflate(R.layout.textview_layout, null, false), mInflater.inflate(R.layout.textview_layout_parent, null),// mInflater.inflate(R.layout.textview_layout_parent, parent), mInflater.inflate(R.layout.textview_layout_parent, parent, false),// mInflater.inflate(R.layout.textview_layout_parent, parent, true), mInflater.inflate(R.layout.textview_layout_parent, null, true), mInflater.inflate(R.layout.textview_layout_parent, null, false), }; convertView = viewList[position]; return convertView; }}效果图:
mInflater.inflate(R.layout.textview_layout, null)
不能正确处理我们设置的宽和高是因为layout_width,layout_height是相对了父级设置的,而此temp的getLayoutParams为null。mInflater.inflate(R.layout.textview_layout, parent)
能正确显示我们设置的宽高是因为我们的View在设置setLayoutParams时params = root.generateLayoutParams(attrs)
不为空。Inflate(resId , parent,false ) 可以正确处理,因为temp.setLayoutParams(params);这个params正是root.generateLayoutParams(attrs);得到的mInflater.inflate(R.layout.textview_layout, null, true)与mInflater.inflate(R.layout.textview_layout, null, false)
不能正确处理我们设置的宽和高是因为layout_width,layout_height是相对了父级设置的,而此temp的getLayoutParams为null- textview_layout_parent.xml作为item可以正确显示的原因是因为TextView具备上级ViewGroup,上级ViewGroup的layout_width,layout_height会失效,当前的TextView会有效而已。
4,布局优化技巧
http://blog.csdn.net/yanbober/article/details/45970721
0 0
- LayoutInflater 分析
- LayoutInflater分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- Android LayoutInflater原理分析
- LayoutInflater源码分析
- 深入分析LayoutInflater
- android LayoutInflater原理分析
- LayoutInflater源码分析
- LayoutInflater 源码分析
- Android LayoutInflater分析
- Android-LayoutInflater分析
- Android LayoutInflater原理分析
- 源码分析之LayoutInflater
- 【SSH网上商城项目实战21】从Demo中看易宝支付的流程
- Android基础控件ListView的使用与焦点冲突解决
- 宝宝小爬虫Selenium自动获取网页cookie+Curl数据查询
- Android进阶之路
- 使用Qt编写模块化插件式应用程序
- LayoutInflater 分析
- 类的加载机制
- 原生JS查找同辈元素
- 你说看到的那些技术问题
- jQuery.parseJSON() 函数详解
- Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式等)介绍
- 浅谈node.js Express框架
- get/post 提交表单乱码的问题
- Spring MVC之@RequestMapping 详解