Xml转换成view的原理

来源:互联网 发布:网络结婚证制作软件 编辑:程序博客网 时间:2024/06/02 03:47

在开发过程中,我们通常都有在用View.inflate(context, resource, root)方法来创建视图,这个方法非常方便,但是它有个缺点就是没有加载xml 里面设置的布局参数。举个例子创建一个叫ListViewDemo 的工程。它里面主界面布局里面就放置一个listview

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent">  <ListView      android:id="@+id/listview"      android:layout_width="match_parent"      android:layout_height="match_parent" /> </RelativeLayout>

在activity 中就是获取到listview 控件并给它设置一个适配器

MainActivity .java

package com.itheima.listviewdemo;    import android.os.Bundle;    import android.app.Activity;    import android.content.Context;    import android.view.LayoutInflater;    import android.view.Menu;    import android.view.View;    import android.view.ViewGroup;    import android.widget.BaseAdapter;    import android.widget.ListView;    public class MainActivity extends Activity {        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            ListView listview = (ListView) findViewById(R.id.listview);            listview.setAdapter(new MyAdapater(this));        }        private class MyAdapater extends BaseAdapter {            private LayoutInflater mInflater;            public MyAdapater(Context mcontext) {                mInflater = (LayoutInflater) mcontext                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);            }            @Override            public int getCount() {                // TODO Auto-generated method stub                return 10;            }            @Override            public Object getItem(int position) {                // TODO Auto-generated method stub                return null;            }            @Override            public long getItemId(int position) {                // TODO Auto-generated method stub                return 0;            }            @Override            public View getView(int position, View convertView, ViewGroup parent) {                View view = mInflater.inflate(R.layout.item, parent, false);                // View view = mInflater.inflate(R.layout.item, null);                return view;            }        }    }

listview 的item 布局为item.xml,它是一个宽度为match_parent,高度为100dp 的线性
布局,线性布局包含了一个宽度为match_parent、高度为match_parent 的TextView。
【文件1-3】item.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="100dp"android:orientation="vertical" ><TextView android:layout_width="match_parent"android:layout_height="match_parent"android:background="#f00"android:text="黑马程序员"/> </LinearLayout>

从布局上来看,listview 的条目textview 控件的高度应该为100dp。但是我们在适配器方法getview 中使用mInflater.inflate(R.layout.item, null)方法后(见【文件1-2】54 行),运行的效果如图1-1(a)所示,它的高
度为包裹内容,这说明它没有使用到xml 中设置的属性高度。

ListViewDemo 运行效果

inflate

如果使用mInflater.inflate(R.layout.item, parent, false),运行效果如图1-1(b)所示,它的高度为100dp,
这样xml 里设置的高度就生效了,这才是inflate 方法的正确用法。
那我们来看看它为什么可以正确显示xml 布局中的数据。我按住ctrl+左键进入mInflater.inflate
(R.layout.item, parent, false) 方法的源码,方法中通过第一个参数布局资源id 获取到一个XmlResourceParser
对象,接着调用inflate(parser, root, attachToRoot)方法(见【文件1-4】3~5 行)。在该方法中首先通过final
AttributeSet attrs = Xml.asAttributeSet(parser) 这段代码拿到xml 中的属性值; 再通过temp =
createViewFromTag(root, name, attrs) 这段代码得到根据属性值attrs 对象创建出来的view 。
createViewFromTag(root, name, attrs)方法中通过调用createView 方法使用反射的方式创建出控件对象;在
inflate(parser, root, attachToRoot)方法中还有一步重要的操作:temp.setLayoutParams(params),这里temp 的
是上面createViewFromTag 方法根据xml 创建出来的view,给它设置了xml 里设置的布局参数,这样xml
里设置的高度就生效了。(这里源码过多就不贴出来了)
源码执行顺序:inflate(R.layout.item, parent,false)→XmlResourceParser →inflate(parser, root,
attachToRoot)→AttributeSet attrs = Xml.asAttributeSet(parser)→temp = createViewFromTag(root, name, attrs)→
→temp.setLayoutParams(params),这是inflate 方法的执行顺序。其中createViewFromTag(root, name, attrs)
方法中通过view = createView(name, null, attrs)方法使用反射来创建xml 中的控件,这样一个xml 转换为
view 的步骤原理就介绍完了。
【文件1-4】Inflate 源码

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(); } }
0 0
原创粉丝点击