LayoutInflater 原理分析 示例

LayoutInflater简介


一. LayoutInflater 简介

       LayoutInflater 顾名思义就是布局填充器,做过Android界面编程,相信对这个类都比较熟悉,可能用人说,我们在activity中使用setContentView(Id)来初始化布局,但实际上其内部也是使用LayoutInflater 来填充布局的。

二. 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 来填充布局的

      可能又有人说,我用setContentView(id)设置布局的,其实setContentView方法的内部也是使用LayoutInflater来加载布局的,只不过这部分源码是internal的,不太容易查看到。

三. LayoutInflater 内部原理

     通过LayoutInflater.inflate()填充布局,主要有如下填充方法:

  

    最终都会调用到 inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)。

测试一


<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);

        View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);

        setContentView(view);

    }

}

结果:这个按钮的大小占了全屏

因为没有父控件时,view的 layout_width 等属性是没有效果的

下面的效果及原理和上面一样 public class MainActivity extends Activity {     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         Button button = new Button(this);         button.setText("代码中创建View");         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, 200);         button.setLayoutParams(layoutParams);         setContentView(button);     } }

测试二


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content" >

    <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);

        setContentView(view);

    }

}

结果:这个按钮的大小和我们的要求完全一致

因为外部有一个父控件,所以view的 layout_width 等属性有效果

下面的效果及原理和上面一样 public class MainActivity extends Activity {     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         Button button = new Button(this);         button.setText("代码中创建View");         RelativeLayout  relativeLayout=new RelativeLayout(this);         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, 200*3);         button.setLayoutParams(layoutParams);         relativeLayout.addView(button);         setContentView(relativeLayout);     } }

测试三


<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(R.layout.activity_main)的时候,系统会默认的加一个父布局Framlayout,这也就是为什么叫setContentView而不是叫setView的原因。

测试四


<Button xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="wrap_content"

    android:layout_height="200dp"

    android:id="@+id/btn"

    android:text="测试按钮" />

public class MainActivity extends Activity {

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        View view = findViewById(R.id.btn);

        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();//最外层有一个FrameLayout

        layoutParams.width = 200 * 2;

        layoutParams.height = 200 * 2;

        view.setLayoutParams(layoutParams);

    }

}

结果:这个按钮的大小和我们的要求完全一致,说明button外层确实有一个FrameLayout。

public class MainActivity extends Activity {     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         Button button = new Button(this);         button.setText("代码中创建View");         FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) button.getLayoutParams();//最外层有一个FrameLayout         if (layoutParams == null) {             Toast.makeText(this, "根本就不存在LayoutParams", Toast.LENGTH_SHORT).show();         }         setContentView(button);     } } 结果:根本就不存在layoutParams,也不存在父布局

bug分析


首先,方法 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);         FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();//最外层有一个FrameLayout         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的原因。

来自为知笔记(Wiz)

时间: 2024-10-24 18:21:55

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

Android LayoutInflater原理分析关于LayoutInflater

Android LayoutInflater原理分析 http://blog.csdn.net/guolin_blog/article/details/12921889

Android 中LayoutInflater原理分析

概述 在Android开发中LayoutInflater的应用非常普遍,可以将res/layout/下的xml布局文件,实例化为一个View或者ViewGroup的控件.与findViewById的作用类似,但是findViewById在xml布局文件中查找具体的控件,两者并不完全相同. 应用场景: 1.在一个没有载入或者想要动态载入的界面中,需要使用layoutInflater.inflate()来载入布局文件: 2.对于一个已经载入的界面,就可以使用findViewById方法来获得其中的界

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

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有段时间没写博客了,感觉都有些生疏了呢.最近繁忙的工作终于告一段落,又有时间写文章了,接下来还会继续坚持每一周篇的节奏. 有 不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲View的工作原理以及自定义View的方法.没错,承诺过的文章我是一定要兑现的,而 且在View这个话题上我还准备多写几篇,尽量能将这个知识点讲得透彻一些.那么今天就从Layout

*Android LayoutInflater原理分析

相信接触Android久一点的朋友对于LayoutInflater一定不会陌生,都会知道它主要是用于加载布局的.而刚接触Android的朋友可能对LayoutInflater不怎么熟悉,因为加载布局的任务通常都是在Activity中调用setContentView()方法来完成的.其实setContentView()方法的内部也是使用LayoutInflater来加载布局的,只不过这部分源码是internal的,不太容易查看到.那么今天我们就来把LayoutInflater的工作流程仔细地剖析一

转:深入理解View--1 LayoutInflater 原理分析

转自:http://blog.csdn.net/guolin_blog/article/details/12921889 先来看一下LayoutInflater的基本用法吧,它的用法非常简单,首先需要获取到LayoutInflater的实例,有两种方法可以获取到,第一种写法如下: [java] view plaincopy LayoutInflater layoutInflater = LayoutInflater.from(context); 当然,还有另外一种写法也可以完成同样的效果: [j

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

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有段时间没写博客了,感觉都有些生疏了呢.最近繁忙的工作终于告一段落,又有时间写文章了,接下来还会继续坚持每一周篇的节奏. 有不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲View的工作原理以及自定义View的方法.没错,承诺过的文章我是一定要兑现的,而且在View这个话题上我还准备多写几篇,尽量能将这个知识点讲得透彻一些.那么今天就从LayoutIn

RemoteViews原理分析及应用

转载请注明出处:http://blog.csdn.net/ahence/article/details/62418926 RemoteViews基本概念 RemoteViews乍一看名字似乎也是一种View,实则不然,它并不是View.来看RemoteViews的定义及官方说明: /** * A class that describes a view hierarchy that can be displayed in * another process. The hierarchy is in

Android视图SurfaceView的实现原理分析

附:Android控件TextView的实现原理分析 来源:http://blog.csdn.net/luoshengyang/article/details/8661317 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制.又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输

AbstractQueuedSynchronizer的介绍和原理分析(转)

简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态.然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作: java.util.concurrent.locks.Abstra