Android:LayoutInflater(布局服务)的 简单介绍 使用方法解析
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! 这个时候用到LayoutParams
的addRule( )方法
!可以添加多个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(布局服务)的 简单介绍 使用方法解析相关推荐
- Android AccountManager 账户同步管理简单介绍
Android AccountManager 账户同步管理简单介绍 文章目录 Android AccountManager 账户同步管理简单介绍 前言 AccountManager 简介 如何让自己的 ...
- Android中PackageManager类的简单介绍
1.PackageManager这个类,表层意思是包管理者,既然可以管理包,那么包下的一些东西便可以获取,其中可以获取应用图标和应用名称以及包名. 通过下面一行代码实例化PackageManager类 ...
- JMS(Java消息服务)(Activemq简单介绍)
是什么? JMS(java消息服务)是规范,它定义了一些规则,一些接口.具体实现由各种做这个产品的厂家或开源组织来实现. 为什么? 在JMS还没有诞生前,每个企业都会有自己的一套内部消息系统,比如项目 ...
- Android 手机重力感应实现简单介绍
手机重力感应实现简单介绍 现在有很多游戏是通过摇晃手机实现的,比如赛车游戏 摇骰子游戏 迷宫游戏 等等 . 今天我用简单的代码为大家介绍一下android 下重力感应的实现方式 ...
- Android开源框架PowerfulViewLibrary——PowerfulEditText的介绍和源码解析
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请注明出处:http://blog.csdn.net/chay_chan/article/details/63685905 An ...
- android必须服务,说说在Android如何使用服务(Service)的方法
Android 服务(Service)适合执行那些不需要和用户交互而且还要求长期运行的任务. 服务的运行不依赖于任何用户界面,即使 APP 被切换到后台,或者打开了另外一个 APP,服务仍然能够保持正 ...
- 【Android】二进制图片和Bitmap的getPixel方法解析
Android中Bitmap的getPixel方法解析 第一次写博客,一直想动笔,但是感觉想写的东西网上都有很详细的了...今天终于下定决心,写第一篇博客.感觉博客这个东西,别人的和自己的是不一样的, ...
- Android数据存储SP的简单介绍
介绍 数据保存分类(目前主流):SP.SQLite.Room 1 SP:sharedPreference首选项 很小,简单的数据可以保存在SP window 的.ini文件,android 的.xml ...
- Android学习之四大组件简单介绍
组件是可以调用的基本功能模块.Android的应用程序就是由组件组成的,Android系统中有四个重要的组件,分别是Activity(活动).Service(服务).BroadcaseReceiver ...
- Android开发之IPC进程间通信-AIDL介绍及实例解析
一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...
最新文章
- android置组件下面,Android Jetpack架构组件(十二)之Hilt
- python中几种读取文件的方法_python 逐行读取文件的几种方法
- uva 815之理解诡异的海平线题目之不容易
- 关于数据中心的选址大全
- @RequestParam和@RequestBody的区别 (结合 Get/Post )
- main spring启动_SpringBoot学习(一):为什么main方法启动类需要放在项目根目录...
- media recovery oracle,Oracle非归档模式Media Recovery错误之--ORA-26040
- mysql binlog 统计_对MySQL binlog日志解析,统计每张表的DML次数
- linux 蓝牙脚本,linux下蓝牙开发(bluez应用)
- Git如何处理代码冲突
- 7-6 实现图形接口及多态性 (30 分)
- ubuntu 14.04 修改PS1提示符
- SonicWall:速度修复这些严重的 SMA 100 漏洞
- c语言怎么储存字母,c语言怎么用变量存储中文字符?书本上面没有的秘密
- 生命在此定格 路透记者遇难前拍下的最后画面
- 2021中兴捧月神算师算法赛,4-24第一场,第二题:B - 切绳子,2021-4-27
- 如何彻底清理注册表?
- 平面的投影变换(1)——什么是投影变换?
- 词向量表示:word2vec与词嵌入
- 【Matlab系列】常用模拟和数字通信系统仿真及Matlab实现
热门文章
- win10编译OpenCV4Android系列2-编译OpenCV4.5.2+opencv_contrib
- MTK最新工具(刷机,写号,升级等)合集含工具源码
- 计算机函数年龄怎么解决,使用Excel函数计算年龄的三种方法
- 网络邻居无法查找计算机,局域网中无法找到网上邻居的原因
- 3t studio 导出数据_Studio 3t for MongoDB 最好的MongoDB工具
- 三角网格上高斯曲率和平均曲率
- 30天扣篮训练计划_高强度减脂训练计划,每天练30分钟,坚持一个月,减掉多余的脂肪...
- html css纯写桌球运动轨迹,纯JS实现椭圆轨迹运动的代码
- 善领dsa2020最新车机ce版_科技测丨需要在车机和手机中“二选一”的凯迪拉克
- Design1.CMOS工艺OD门,传输门,三态门原理应用浅析