Xml转换成view的原理

    xiaoxiao2021-12-14  24

    在开发过程中,我们通常都有在用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 运行效果

    如果使用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(); } }
    转载请注明原文地址: https://ju.6miu.com/read-971497.html

    最新回复(0)