Xml转换成view的原理

本文探讨了在Android开发中,如何使用View.inflate()方法正确加载XML布局,特别是如何处理布局参数。通过分析源码,解释了当attachToRoot参数为true和false时的不同行为,强调了正确设置此参数以确保XML中定义的布局属性得以生效的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发过程中,我们通常都有在用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();
 }
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值