LayoutInflater简介

       LayoutInflater 顾名思义就是布局填充器,做过Android界面编程,相信对这个类都比较熟悉,可能有人说,我们在activity中使用setContentView(Id)来初始化布局,但实际上其内部也是使用LayoutInflater 来填充布局的。
      可以通过以下两种方式获取LayoutInflater
           1. LayoutInflater layoutInflater = LayoutInflater.from(context);
           2. LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)
      然后再调用 layoutInflater.inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 来获取View
      可能有的同学使用View.inflate()获取View的,那我们进去看下:
  public static View inflate(Context context, int resource, ViewGroup root) {
        LayoutInflater factory = LayoutInflater.from(context);
        return factory.inflate(resource, root);
    }
      其实最终还是通过LayoutInflater 来填充布局的
     通过LayoutInflater.inflate()填充布局,主要有如下填充方法:
  
    最终都会调用到 inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)。

1、使用setContentView(View)

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:text="测试按钮" />
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //当使用inflate(layout, null)时,layout最外层的控件的宽高是没有效果的,所以最外层控件宽高会变成match_parent
        View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
        //布局前view没有父控件,此时view.getParent()及view.getLayoutParams()都为空
        Toast.makeText(this, "布局前是否没有父布局:" + (view.getParent() == null), Toast.LENGTH_SHORT).show();//true
        setContentView(view);
        Toast.makeText(this, "布局后父布局是否为FrameLayout:" + (view.getParent() instanceof FrameLayout) + "", Toast.LENGTH_SHORT).show();//true
    }
}
结果:这个按钮的大小占了全屏。
解释:因为在布局时,View没有父控件,所以view(即Button)的 layout_width 等属性是没有效果的。
注意:在setContentView(***)的时候,系统会默认的加一个父布局Framlayout,这也就是为什么叫setContentView而不是叫setView的原因。
下面的效果及原理和上面一样,在没有父控件时,setLayoutParams也是没有效果的。
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button view = new Button(this);
        view.setText("代码中创建View");
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 200);
        view.setLayoutParams(layoutParams);
        Toast.makeText(this, "布局前是否没有父布局:" + (view.getParent() == null), Toast.LENGTH_SHORT).show();//true
        setContentView(view);
        Toast.makeText(this, "布局后父布局是否为FrameLayout:" + (view.getParent() instanceof FrameLayout) + "", Toast.LENGTH_SHORT).show();//true
    }

}


2、使用setContentView(ViewGroup)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="300dp"
    android:background="#f00" >
    <Button
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:text="测试按钮" />
</RelativeLayout>
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
        //当使用inflate(layout, null)时,layout最外层的控件的宽高是没有效果的,所以最外层控件宽高会变成match_parent。但是内层控件的宽高还是有效的。
        Toast.makeText(this, "view是否是xml中的父布局:" + (view instanceof RelativeLayout), Toast.LENGTH_SHORT).show();//true
        setContentView(view);
        Toast.makeText(this, "布局后view的父布局是否为FrameLayout:" + (view.getParent() instanceof FrameLayout) + "", Toast.LENGTH_SHORT).show();//true
    }
}
结果:背景全屏都是红色,但按钮的大小和我们希望的一致。
解释:因为Button外部有一个父控件,所以Button的layout_width等属性有效果;而RelativeLayout外部没有父控件,所以其layout_width等属性没有效果。
注意:仅仅是layout_***等属性没效果,但是background等属性还是有效果的。
下面的效果及原理和上面一样
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button view = new Button(this);
        view.setText("代码中创建View");
        RelativeLayout relativeLayout = new RelativeLayout(this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 200 * 3);
        //注意,view.setLayoutParams(layoutParams)方法中的参数是作用到view上的,在view没有父布局时用哪个Layout的LayoutParams都可以
        view.setLayoutParams(layoutParams);
        relativeLayout.addView(view);
        //view.setLayoutParams(layoutParams);//将view添加到RelativeLayout后,就不能再使用其他Layout的LayoutParams了,否则报类型转换异常
        Toast.makeText(this, "布局前父布局是否为RelativeLayout:" + (view.getParent() instanceof RelativeLayout) + "", Toast.LENGTH_SHORT).show();//true
        setContentView(relativeLayout);
        Toast.makeText(this, "布局后父布局的父布局是否为FrameLayout:" + (view.getParent().getParent() instanceof FrameLayout) + "", Toast.LENGTH_SHORT).show();//true
    }

}


3、使用setContentView(Int layout)

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:text="测试按钮" />
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
结果:这个按钮的大小和我们希望的一致。
解释:setContentView(Int layout)方法和其他重载方法不太一样,他会先把xml中的布局加到根部的FrameLayout上再进行布局,所以在布局时Button是由父布局的。
下面的效果和道理和上面的一样

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button view = new Button(this);
        view.setText("代码中创建View");
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 200 * 3);
        setContentView(view, layoutParams);
        //注意,button的父布局不是上面定义layoutParams时用的RelativeLayout,而是系统默认加上的FrameLayout
        Toast.makeText(this, "布局后父布局是否为FrameLayout:" + (view.getParent() instanceof FrameLayout) + "", Toast.LENGTH_SHORT).show();//true
    }

}


总结

首先,方法 inflate(int resource, ViewGroup root)会调用inflate(int resourceId, ViewGroup root, boolean attachToRoot)方法,并且如果root不为null,则attachToRoot 为true。
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }
下面我们来分析inflate(int resourceId, ViewGroup root, boolean attachToRoot)中这三个参数的作用
首先:resourceId 就是布局Id,root是这个布局所依附的父布局, attachToRoot就是是否依附在这个父布局上,下面分情况讨论下。
  • root 不为null,attachToRoot 为 false:resource的最外层的控件的宽高是有效果的,但不会添加到父控件中
  • root 不为null,attachToRoot 为 true: resource的最外层的控件的宽高是有效果的,并且会添加到父控件中
  • root 若为null,此时 attachToRoot 的值将不起作用,resource的最外层的控件的宽高是【没有】效果的,并且会添加到父控件中
为什么呢?大家再回忆一下,我们怎么动态修改View的宽和高,代码如下:
        View view = findViewById(R.id.btn);
        ***Layout.LayoutParams layoutParams = (***Layout.LayoutParams) view.getLayoutParams();
        layoutParams.width = 200 * 2;
        layoutParams.height = 200 * 2;
        view.setLayoutParams(layoutParams);  
为什么不是直接获取View设置View的大小而是去设置View的 LayoutParams呢?
这是因为我们在设置一个View的layout_width、layout_height、padding 的值的时候,其实这些属性都是作用在父布局中的,并不是作用于View上的,这也是为什么叫layout_width而不是width的原因。
所以若没有父布局,你设置的这些layout_***属性都是无效的。
但若你xml中是一个多层的布局,则只是最外层的这些属性无效,里面控件的属性还是有效的。

LayoutInflater 原理分析 示例的更多相关文章

  1. Android视图SurfaceView的实现原理分析(示例,出错代码)

    在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独 ...

  2. Android LayoutInflater原理分析,带你一步步深入了解View(一)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲Vi ...

  3. Android LayoutInflater原理分析

    相信接触Android久一点的朋友对于LayoutInflater一定不会陌生,都会知道它主要是用于加载布局的.而刚接触Android的朋友可能对LayoutInflater不怎么熟悉,因为加载布局的 ...

  4. 安卓主activity引用自定义的View——Android LayoutInflater原理分析

    相信接触Android久一点的朋友对于LayoutInflater一定不会陌生,都会知道它主要是用于加载布局的.而刚接触Android的朋友可能对LayoutInflater不怎么熟悉,因为加载布局的 ...

  5. seo伪原创技术原理分析,php实现伪原创示例

    seo伪原创技术原理分析,php实现伪原创示例 现在seo伪原创一般采用分词引擎以及动态同义词库,模拟百度(baidu),谷歌(google)等中文切词进行伪原创,生成后的伪原创文章更准确更贴近百度和 ...

  6. Java NIO使用及原理分析(1-4)(转)

    转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...

  7. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

  8. 转载:AbstractQueuedSynchronizer的介绍和原理分析

    简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过 ...

  9. Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

    概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...

随机推荐

  1. oracle单行函数之日期函数

    在日期上加上或减去一个数字结果仍为日期. 两个日期相减返回日期之间相差的天数. 可以用数字除24来向日期中加上或减去小时. SQL from dual; SYSDATE SYSDATE ------- ...

  2. 数据库SQLite在Qt5+VS2012使用规则总结---中文乱码

    VS2012默认格式为 "GB2312-80",而有时我们用到字符串需要显示中文时,就会出现乱码.下面仅就Qt5和VS2012中使用数据库SQLite时,做一个简单的备忘录 #in ...

  3. :after伪类+content内容生成经典应用举例

    一.简单说说content内容生成 content内容生成就是通过content属性生成内容,content属性早在CSS2.1的时候就被引入了,可以使用:before以及:after伪元素生成内容. ...

  4. linux 添加 $path

    # vim /etc/profile在文档最后,添加:export PATH="/usr/local/src/bin:$PATH"保存,退出,然后运行:#source /etc/p ...

  5. 不要依赖hibernate的二级缓存

    一.hibernate的二级缓存   如果开启了二级缓存,hibernate在执行任何一次查询的之后,都会把得到的结果集放到缓存中,缓存结构可以看作是一个hash table,key是数据库记录的id ...

  6. Python操作excel(xlrd和xlwt)

    Python操作excel表格有很多支持的库,例如:xlrd.xlwt.openpyxl.win32com,下面介绍使用xlrd.xlwt和xlutils模块这三个库不需要其他的支持,在任何操作系统上 ...

  7. 搭建splinter+python环境时遇到的错误

    因为不想用urllib2了,没有用过splinter,今天就想试试,毕竟后者支持的功能更人性化/自动化. 1,安装splinter 安装过程很简单,安装了pip的话,执行: $ [sudo] pip ...

  8. 02 - 替换SetInput方法 VTK 6.0 迁移 (2013-06-30 16:22)

    VTK6 引入了许多不兼容的变化,这其中就包括用SetInputData()和SetInputConnection()替换SetInput()方法.在先前的版本中,VTK4 引入了SetInput() ...

  9. IE中对于stylesheet的个数限制

    对于IE6-9: 1.样式规则最多只能有4095个,多于这个数目的会被忽略: 2.样式表(通过@import, <link> 或 <style>)最多可以有31个(总和),多于 ...

  10. 系统共享内存的修改(ORA-27102: out of memory)

    http://ccchencheng.blog.51cto.com/2419062/738188 http://blog.csdn.net/leshami/article/details/874602 ...