LayoutInflater布局服务

  • LayoutInflater
    • 1、什么是LayoutInflater?
    • 2、如何调用inflate()函数
    • 3、inflate()方法参数解析
      • 3.1、attachToRoot何时为true,何时为false?
      • 3.2、LayoutInflater.from这个方法什么意思?
    • 4、Java代码加载布局使用流程
    • 5、Java代码动态加载xml布局
  • 参考

LayoutInflater

1、什么是LayoutInflater?

Layout是什么?

答:一个用于加载布局的系统服务,就是实例化与Layout XML文件对应的View对象,不能直接使用,需要通过getLayoutInflater( )方法或getSystemService( )方法来获得与当前Context绑定的LayoutInflater实例!

说到布局,大家第一时间 可能想起的是写完一个布局的xml,然后调用Activity的setContentView()加载布局,然后把他显示 到屏幕上是吧~其实这个底层走的还是这个LayoutInflater。

在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。不同点是:

  • LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;
  • 而findViewById()是找xml布局文件下的具体widget控件(如 Button、TextView等)。

具体作用:

  • 1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
  • 2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。

2、如何调用inflate()函数

LayoutInflater.inflate()这个方法,大家一定很熟悉——在给fragment添加布局文件,或者在RecyclerView的Adapter中item添加布局时,都会用到。

如何调用inflate()函数?

  • 首先要获得一个LayoutInflater的实例,有三种方法,这三种方法实质上是相同的,最常用的是第一种。
LayoutInflater inflater1 = LayoutInflater.from(this);  LayoutInflater inflater2 = getLayoutInflater();  LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
  • 然后使用这个实例调用inflate方法
inflater.inflate(xxxxxxx)

3、inflate()方法参数解析

1、三个参数

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
  • 第一个参数:要获取的布局(加载的布局对应的资源id),传入R.layout.xxx
  • 第二个参数:这个参数也是一个布局,是为第一个参数指定的父布局。如果不需要的话,写null就可以了!
  • 第三个参数:是否为加载的布局文件的最外层套一层root布局,不设置该参数的话, 如果root不为null的话,则默认为true 如果root为null的话,attachToRoot就没有作用了! root不为null,attachToRoot为true的话,会在加载的布局文件最外层嵌套一层root布局; 为false的话,则root失去作用! 简单理解就是:是否为加载的布局添加一个root的外层容器~!
    • true:将第一个参数表示的布局添加到第二参数的布局中。
    • false:不将第一个参数表示的布局添加到第二参数的布局中。

既然不添加,那么为什么第二个参数不设置为null呢。

  • 不添加的话,这个函数就只剩下一个作用了,那就是获取布局,为了使第一个参数的宽高属性不失效,所以要为他指定一个父布局。

具体可以参考源码:

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    synchronized (mConstructorArgs) {    final AttributeSet attrs = Xml.asAttributeSet(parser);    mConstructorArgs[0] = mContext;    View result = root;    try {    int type;    while ((type = parser.next()) != XmlPullParser.START_TAG &&    type != XmlPullParser.END_DOCUMENT) {    }    if (type != XmlPullParser.START_TAG) {    throw new InflateException(parser.getPositionDescription()    + ": No start tag found!");    }    final String name = parser.getName();    if (TAG_MERGE.equals(name)) {    if (root == null || !attachToRoot) {    throw new InflateException("merge can be used only with a valid "    + "ViewGroup root and attachToRoot=true");    }    rInflate(parser, root, attrs);    } else {    View temp = createViewFromTag(name, attrs);    ViewGroup.LayoutParams params = null;    if (root != null) {    params = root.generateLayoutParams(attrs);    if (!attachToRoot) {    temp.setLayoutParams(params);    }    }    rInflate(parser, temp, attrs);    if (root != null && attachToRoot) {    root.addView(temp, params);    }    if (root == null || !attachToRoot) {    result = temp;    }    }    } catch (XmlPullParserException e) {    InflateException ex = new InflateException(e.getMessage());    ex.initCause(e);    throw ex;    } catch (IOException e) {    InflateException ex = new InflateException(    parser.getPositionDescription()    + ": " + e.getMessage());    ex.initCause(e);    throw ex;    }    return result;    }
}

总结一下,就是:

  • 若attachToRoot为true且root不为null,则调用root.addView()方法
  • 若root为null,或者attachToRoot为false,则直接将temp赋于result(temp是通过root构造的,result就是root)

2、两个参数

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
  • 第一个参数:要获取的布局,传入R.layout.xxx
  • 第二个参数:这个参数也是一个布局,是为第一个参数指定的父布局。
    • 如果这个参数是null就不把第一个参数的布局添加进来
    • 如果这个参数不是null就把第一个参数的布局添加进来

查看源码它其实还是调用三个参数的

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
{return inflate(resource, root, root != null);
}

3.1、attachToRoot何时为true,何时为false?

就拿我们的Adapter来说吧,在创建item布局时,有下列几种情况:

inflate(R.layout.xxx,null);
inflate(R.layout.xxx,parent,false);
inflate(R.layout.xxx,parent,true);

那么就讲一下这三种情况把。

首先,inflate(R.layout.xxx,null) 。这是最简单的写法,这样生成的布局就是根据http://R.layout.xxx返回的View。要知道,这个布局文件中的宽高属性都是相当于父布局而言的。由于没有指定parent,所以他的宽高属性就失效了,因此不管你怎么改宽高属性,都无法按你想象的那样显示。

然后,inflate(R.layout.xxx,parent,false)。相较于前者,这里加了父布局,不管后面是true还是false,由于有了parent,布局文件的宽高属性是有依靠了,这时候显示的宽高样式就是布局文件中的那样了。

最后,inflate(R.layout.xxx,parent,true)。这样……等等,报错了???哦,不要惊奇,分析一下原因:首先,有了parent,所以可以正确处理布局文件的宽高属性。然后,既然attachToRoot为true,那么根据上面的源码就会知道,这里会调用root的addView方法。而如果root是listView等,由于他们是继承自AdapterView的,看看AdapterView的addView方法:

@Overridepublic void addView(View child) {throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");}

不支持啊,那好吧,如果换成RecyclerView呢?还是报错了,看看源码:

if (child.getParent() != null) {throw new IllegalStateException("The specified child already has a parent. " +"You must call removeView() on the child's parent first.");}

现在知道了吧,adpater里面不要用true。那么什么时候用true呢?答案是fragment。在为fragment创建布局时,如果为true,那么这个布局文件就会被添加到父activity中盛放fragment的布局中。

实例参考

3.2、LayoutInflater.from这个方法什么意思?

从一个Context中,获得一个布局填充器,这样你就可以使用这个填充器来把xml布局文件转为View对象了。

//加载布局管理器
LayoutInflater inflater = LayoutInflater.from(context);//将xml布局转换为view对象
convertView = inflater.inflate(R.layout.item_myseallist,parent, false);//利用view对象,找到布局中的组件
convertView.findViewById(R.id.delete);

因为在一个Activity里如果直接用findViewById()的话,对应的是setConentView()的那个layout里的组件.
因此如果你的Activity里如果用到别的layout,比如对话框上的layout,你还要设置对话框上的layout里的组件(像图片ImageView,文字TextView)上的内容,你就必须用inflate()先将对话框上的layout找出来,然后再用这个layout对象去找到它上面的组件,如:

View view = View.inflate(this, R.layout.dialog_layout, null);TextView dialogTV = (TextView) view.findViewById(R.id.dialog_tv);dialogTV.setText("abcd");

如果组件R.id.dialog_tv是对话框上的组件,而你直接用this.findViewById(R.id.dialog_tv)肯定会报错.

4、Java代码加载布局使用流程

Step 1:

①创建容器:LinearLayout ly = new LinearLayout(this);②创建组件:Button btnOne = new Button(this);

Step 2:
可以为容器或者组件设置相关属性:

  • 比如:LinearLayout,我们可以设置组件的排列方向:ly.setOrientation(LinearLayout.VERTICAL);
  • 而组件也可以:比如Button:btnOne.setText("按钮1");
  • 关于设置属性的方法可参见Android 的API,通常xml设置的属性只需在前面添加:set即可,比如setPadding(左,上,右,下);

Step 3:

将组件或容器添加到容器中,这个时候我们可能需要设置下组件的添加位置,或者设置他的大小: 我们需要用到一个类:LayoutParams,我们可以把它看成布局容器的一个信息包!封装位置与大小 等信息的一个类!先演示下设置大小的方法:(前面的LinearLayout可以根据不同容器进行更改)

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

很简单,接着就到这个设置位置了,设置位置的话,通常我们考虑的只是RelativeLayout! 这个时候用到LayoutParamsaddRule( )方法!可以添加多个addRule( )哦! 设置组件在父容器中的位置,
比如设置组件的对其方式:

RelativeLayout rly = new RelativeLayout(this);
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
Button btnOne = new Button(this);
rly.addView(btnOne, lp2);

参照其他组件的对其方式: (有个缺点,就是要为参考组件手动设置一个id,是手动!!!) 比如:设置btnOne居中后,让BtnTwo位于btnOne的下方以及父容器的右边!

public class MainActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  RelativeLayout rly = new RelativeLayout(this);  Button btnOne = new Button(this);  btnOne.setText("按钮1");  Button btnTwo = new Button(this);  btnTwo.setText("按钮2");  // 为按钮1设置一个id值  btnOne.setId(123);  // 设置按钮1的位置,在父容器中居中  RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  // 设置按钮2的位置,在按钮1的下方,并且对齐父容器右面  RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  rlp2.addRule(RelativeLayout.BELOW, 123);  rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  // 将组件添加到外部容器中  rly.addView(btnTwo, rlp2);  rly.addView(btnOne, rlp1);  // 设置当前视图加载的View即rly  setContentView(rly);  }
}

step 4:

调用setContentView( )方法加载布局对象即可! 另外,如果你想移除某个容器中的View,可以调用容器.removeView(要移除的组件);

运行截图:

5、Java代码动态加载xml布局

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/RelativeLayout1"android:layout_width="match_parent"android:layout_height="match_parent" ><Buttonandroid:id="@+id/btnLoad"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="动态加载布局"/>
</RelativeLayout>

inflate.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="match_parent"  android:gravity="center"  android:orientation="vertical"  android:id="@+id/ly_inflate" >  <TextView  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="我是Java代码加载的布局" />  <Button  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="我是布局里的一个小按钮" />  </LinearLayout>

接着到我们的MainActivity.java在这里动态加载xml布局:

public class MainActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  //获得LayoutInflater对象;  final LayoutInflater inflater = LayoutInflater.from(this);    //获得外部容器对象  final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  Button btnLoad = (Button) findViewById(R.id.btnLoad);  btnLoad.setOnClickListener(new OnClickListener() {  @Override  public void onClick(View v) {  //加载要添加的布局对象  LinearLayout ly = (LinearLayout) inflater.inflate(  R.layout.inflate, null, false).findViewById(  R.id.ly_inflate);  //设置加载布局的大小与位置  RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    lp.addRule(RelativeLayout.CENTER_IN_PARENT);    rly.addView(ly,lp);  }  });  }
}

参考

1、https://www.runoob.com/w3cnote/android-tutorial-layoutinflater.html
2、https://zhuanlan.zhihu.com/p/23334059

Android:LayoutInflater(布局服务)的 简单介绍 使用方法解析相关推荐

  1. Android AccountManager 账户同步管理简单介绍

    Android AccountManager 账户同步管理简单介绍 文章目录 Android AccountManager 账户同步管理简单介绍 前言 AccountManager 简介 如何让自己的 ...

  2. Android中PackageManager类的简单介绍

    1.PackageManager这个类,表层意思是包管理者,既然可以管理包,那么包下的一些东西便可以获取,其中可以获取应用图标和应用名称以及包名. 通过下面一行代码实例化PackageManager类 ...

  3. JMS(Java消息服务)(Activemq简单介绍)

    是什么? JMS(java消息服务)是规范,它定义了一些规则,一些接口.具体实现由各种做这个产品的厂家或开源组织来实现. 为什么? 在JMS还没有诞生前,每个企业都会有自己的一套内部消息系统,比如项目 ...

  4. Android 手机重力感应实现简单介绍

    手机重力感应实现简单介绍            现在有很多游戏是通过摇晃手机实现的,比如赛车游戏 摇骰子游戏 迷宫游戏 等等 . 今天我用简单的代码为大家介绍一下android 下重力感应的实现方式 ...

  5. Android开源框架PowerfulViewLibrary——PowerfulEditText的介绍和源码解析

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请注明出处:http://blog.csdn.net/chay_chan/article/details/63685905 An ...

  6. android必须服务,说说在Android如何使用服务(Service)的方法

    Android 服务(Service)适合执行那些不需要和用户交互而且还要求长期运行的任务. 服务的运行不依赖于任何用户界面,即使 APP 被切换到后台,或者打开了另外一个 APP,服务仍然能够保持正 ...

  7. 【Android】二进制图片和Bitmap的getPixel方法解析

    Android中Bitmap的getPixel方法解析 第一次写博客,一直想动笔,但是感觉想写的东西网上都有很详细的了...今天终于下定决心,写第一篇博客.感觉博客这个东西,别人的和自己的是不一样的, ...

  8. Android数据存储SP的简单介绍

    介绍 数据保存分类(目前主流):SP.SQLite.Room 1 SP:sharedPreference首选项 很小,简单的数据可以保存在SP window 的.ini文件,android 的.xml ...

  9. Android学习之四大组件简单介绍

    组件是可以调用的基本功能模块.Android的应用程序就是由组件组成的,Android系统中有四个重要的组件,分别是Activity(活动).Service(服务).BroadcaseReceiver ...

  10. Android开发之IPC进程间通信-AIDL介绍及实例解析

    一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...

最新文章

  1. android置组件下面,Android Jetpack架构组件(十二)之Hilt
  2. python中几种读取文件的方法_python 逐行读取文件的几种方法
  3. uva 815之理解诡异的海平线题目之不容易
  4. 关于数据中心的选址大全
  5. @RequestParam和@RequestBody的区别 (结合 Get/Post )
  6. main spring启动_SpringBoot学习(一):为什么main方法启动类需要放在项目根目录...
  7. media recovery oracle,Oracle非归档模式Media Recovery错误之--ORA-26040
  8. mysql binlog 统计_对MySQL binlog日志解析,统计每张表的DML次数
  9. linux 蓝牙脚本,linux下蓝牙开发(bluez应用)
  10. Git如何处理代码冲突
  11. 7-6 实现图形接口及多态性 (30 分)
  12. ubuntu 14.04 修改PS1提示符
  13. SonicWall:速度修复这些严重的 SMA 100 漏洞
  14. c语言怎么储存字母,c语言怎么用变量存储中文字符?书本上面没有的秘密
  15. 生命在此定格 路透记者遇难前拍下的最后画面
  16. 2021中兴捧月神算师算法赛,4-24第一场,第二题:B - 切绳子,2021-4-27
  17. 如何彻底清理注册表?
  18. 平面的投影变换(1)——什么是投影变换?
  19. 词向量表示:word2vec与词嵌入
  20. 【Matlab系列】常用模拟和数字通信系统仿真及Matlab实现

热门文章

  1. win10编译OpenCV4Android系列2-编译OpenCV4.5.2+opencv_contrib
  2. MTK最新工具(刷机,写号,升级等)合集含工具源码
  3. 计算机函数年龄怎么解决,使用Excel函数计算年龄的三种方法
  4. 网络邻居无法查找计算机,局域网中无法找到网上邻居的原因
  5. 3t studio 导出数据_Studio 3t for MongoDB 最好的MongoDB工具
  6. 三角网格上高斯曲率和平均曲率
  7. 30天扣篮训练计划_高强度减脂训练计划,每天练30分钟,坚持一个月,减掉多余的脂肪...
  8. html css纯写桌球运动轨迹,纯JS实现椭圆轨迹运动的代码
  9. 善领dsa2020最新车机ce版_科技测丨需要在车机和手机中“二选一”的凯迪拉克
  10. Design1.CMOS工艺OD门,传输门,三态门原理应用浅析