Android 之 LayoutInflater (布局服务)

本节引言:

 本节继续带来的是Android系统服务中的LayoutInflater(布局服务),说到布局,大家第一时间 可能想起的是写完一个布局的xml,然后调用Activity的setContentView()加载布局,然后把他显示 到屏幕上是吧~其实这个底层走的还是这个LayoutInflater,用的Android内置的Pull解析器来解析 布局。一般在Android动态加载布局或者添加控件用得较多,本节我们就来学习下他在实际开发中 的一些用法~

官方API文档:LayoutInflater


1.LayoutInflater的相关介绍


1)Layout是什么鬼?

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


2)LayoutInflater的用法

①获取LayoutInflater实例的三种方法

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 

PS:后面两个其实底层走的都是第一种方法~

②加载布局的方法

public View inflate (int resource, ViewGroup root, boolean attachToRoot) 该方法的三个参数依次为:

①要加载的布局对应的资源id

②为该布局的外部再嵌套一层父布局,如果不需要的话,写null就可以了!

③是否为加载的布局文件的最外层套一层root布局,不设置该参数的话, 如果root不为null的话,则默认为true 如果root为null的话,attachToRoot就没有作用了! root不为null,attachToRoot为true的话,会在加载的布局文件最外层嵌套一层root布局; 为false的话,则root失去作用! 简单理解就是:是否为加载的布局添加一个root的外层容器~!


③通过LayoutInflater.LayoutParams来设置相关的属性:

比如RelativeLayout还可以通过addRule方法添加规则,就是设置位置:是参考父容器呢? 还是参考子控件?又或者设置margin等等,这个由你决定~


2.纯Java代码加载布局

我们早已习惯了使用XML生成我们需要的布局,但是在一些特定的情况下,我们 需要使用Java代码往我们的布局中动态的添加组件或者布局!

但是不建议大家完全地使用Java代码来编写Android页面布局,首先一点就是代码会多, 一多久容易乱,而且不利于业务的分离,我们还是建议使用xml来完成布局,然后通过 Java代码对里面的组件进行修改,当然有些时候可能需要使用Java动态的来添加组件!

纯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(要移除的组件);

运行截图


3.Java代码动态添加控件或xml布局

第二点我们讲解了使用纯Java代码来加载布局,实际当中用得并不多,更多的时候是动态 的添加View控件以及动态的加载XML布局!

1)Java代码动态增加View

动态添加组件的写法有两种,区别在于是否需要先setContentView(R.layout.activity_main); 下面演示下两种不同写法添加一个Button的例子:

先写个布局文件先: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" >  <TextView   android:id="@+id/txtTitle"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:text="我是xml文件加载的布局"/>  </RelativeLayout>  

第一种不需要setContentView()加载布局文件先:

public class MainActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  Button btnOne = new Button(this);  btnOne.setText("我是动态添加的按钮");  RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    LayoutInflater inflater = LayoutInflater.from(this);  RelativeLayout rly = (RelativeLayout) inflater.inflate(  R.layout.activity_main, null)  .findViewById(R.id.RelativeLayout1);  rly.addView(btnOne,lp2);  setContentView(rly);  }  
} 

第二种不需要setContentView()加载布局文件先:

public class MainActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  Button btnOne = new Button(this);  btnOne.setText("我是动态添加的按钮");  RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  rly.addView(btnOne,lp2);  }  
} 

分析总结

代码很简单,创建按钮后,我们又创建了一个LayoutParams对象,用来设置Button的大小, 又通过addRule()方法设置了Button的位置!

第一种方法:通过LayoutInflate的inflate()方法加载了activity_main布局,获得了外层容器, 接着addView添加按钮进容器,最后setContentView();

第二种方法:因为我们已经通过setContetView()方法加载了布局,此时我们就可以通过 findViewById找到这个外层容器,接着addView,最后setContentView()即可!

另外,关于这个setContentView( )他设置的视图节点是整个XML的根节点!


2)Java代码动态加载xml布局

接下来的话,我们换一个,这次加载的是xml文件!动态地添加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);  }  });  }  
} 

运行截图

代码分析

①获取容器对象:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

②获得Inflater对象,同时加载被添加的布局的xml,通过findViewById找到最外层的根节点

final LayoutInflater inflater = LayoutInflater.from(this);
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);

4.LayoutInflater的inflate()方法源码

最后提供下LayoutInflater的inflate()方法的源码吧,有兴趣的可以看看~,其实就是Pull解析而已~

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/61260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

会话跟踪技术

cookie 是通过在浏览器第一次请求服务器时&#xff0c;在响应中放入cookie&#xff0c;浏览器接收到cookie后保存在本地&#xff0c;之后每次请求服务器时都将cookie携带到请求头中&#xff0c;用来验证用户身份与状态等。 缺点&#xff1a; 移动端app没有cookiecookie保存在…

11月考PMP的考生注意了,请尽快完成英文报名!

PMP 项目管理专业人士资格认证&#xff0c;是经由美国项目管理协会&#xff08;PMI&#xff09;发起&#xff0c;组织的考试&#xff0c;目的是为了给项目管理人员提供统一的行业标准&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。 免费送备考资料。…

直播电商系统源码:搭建属于你自己的直播商城

​ 感谢您选择一一零七科技有限公司&#xff0c;在这里&#xff0c;我们致力于为您提供最佳的商城解决方案。我们引以为豪的产品之一就是独立商城&#xff0c;它将成为您拓展业务、增加盈利的利器。今天&#xff0c;我们将向您介绍这个令人激动的产品&#xff0c;同时展示我们的…

input时间表单默认样式修改(input[type=“date“])

一、时间选择的种类: HTML代码&#xff1a; <input type"date" value"2018-11-15" />选择日期&#xff1a; 选择时间&#xff1a; <input type"time" value"22:52" />在这里插入图片描述 选择星期&#xff1a; <…

JavaScript—数据类型、对象与构造方法

js是什么&#xff1f; JavaScript&#xff08;简称“JS”&#xff09; 是一种具有函数优先的轻量级&#xff0c;解释型或即时编译型的编程语言。JavaScript 基于原型编程、多范式的动态脚本语言&#xff0c;并且支持面向对象、命令式、声明式、函数式编程范式。 js有哪些特点呢…

Java类的声明周期、对象的创建过程

一、类的生命周期 使用类时&#xff0c;要先使用类加载器将类的字节码从磁盘加载到内存的方法区中&#xff0c;用Class对象表示加载到内存中的类&#xff0c;Class类是JDK中提供的类创建对象时&#xff0c;是根据内存中的Class对象&#xff0c;在堆中分配内存&#xff0c;完成…

Servlet与过滤器

目录 Servlet 过滤器 Servlet Servlet做了什么 本身不做任何业务处理,只是接收请求并决定调用哪个JavaBean去处理请求,确定用哪个页面来显示处理返回的数据 Servlet是什么 ServerApplet&#xff0c;是一种服务器端的Java应用程序 只有当一个服务器端的程序使用了Servlet…

网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC

文章目录 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC1. 网御ACM上网行为管理系统简介2.漏洞描述3.影响版本4.fofa查询语句5.漏洞复现6.POC&EXP7.整改意见8.往期回顾 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC 免责声明&am…

自然语言处理(NLP)是什么?

NLP(自然语言处理) 和 Phoebe Liu 的简介 您有没有和聊天机器人互动过&#xff1f;或者您是否向虚拟助手&#xff0c;例如 Siri、Alexa 或您车上的车载娱乐系统发出过某些请求&#xff1f;您使用过在线翻译吗&#xff1f;我们大多数人都曾与这些人工智能 (AI) 互动过&#xff…

自步学习的介绍 self paced learning

这方面的研究专家&#xff0c;参考西安交通大学的 孟德宇老师 他最近的研究方向&#xff1a; Fundamental problems in machine learning and computer vision, especially including: Meta-learning Variational bayesian methods on inverse problems Robust and interpret…

ELK安装、部署、调试(三)zookeeper安装,配置

1.准备 java安装&#xff0c;系统自带即可 2.下载zookeeper zookeeper.apache.org上可以下载 tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /usr/local mv apache-zookeeper-3.7.1-bin zookeeper 3.配置zookeeper mv zoo_sample.cfg zoo.cfg /usr/local/zookeeper/con…

匿名内部类、Lambda、方法引用 的总结

在今天的项目中看到这样一行代码 Integer syncCount consumer.consumerInfo( Collections.singletonList(KafkaTopicConst.Event_BMS_SYSLOG_ROLE),consumer::handle); 直接傻眼&#xff0c;无法理解consumer::handle这种用法&#xff0c;因此总结如下 consumer::handle这种写…

微前端:重塑大型项目的前沿技术

引言 随着互联网技术的飞速发展&#xff0c;前端开发已经从简单的页面制作逐渐转变为复杂的应用开发。在这个过程中&#xff0c;传统的前端开发模式已经难以满足大型项目的需求。微前端作为一种新的前端架构模式&#xff0c;应运而生&#xff0c;它旨在解决大型项目中的前端开…

如何使用 ChatGPT 快速制作播客和其他长篇内容

使用ChatGPT快速制作播客和其他长篇内容是一个高效且具有一定创造性的过程。以下是一些详细的步骤和技巧&#xff0c;以帮助你充分利用ChatGPT来制作高质量的内容。 一、准备阶段 确定主题或话题&#xff1a;在开始制作之前&#xff0c;你需要明确你的播客或长篇内容将聚焦的主…

从0-1的docker镜像服务构建

文章目录 摘要一、环境准备1、docker安装2、docker-compose安装 二、镜像制作2.1、编写Dockerfile文件2.1.1、熟悉常用Dockerfile命令2.1.2、制作php镜像案例 2.2、build镜像 三、docker-compose管理容器3.1、编写docker-compose.ymal配置文件3.2、编写systemctl配置 摘要 由于…

C++-list实现相关细节和问题

前言&#xff1a;C中的最后一个容器就是list&#xff0c;list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指…

【面试经典150题】买卖股票的最佳时期 JavaScript版

题目链接 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…

力扣:77. 组合(Python3)

题目&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平…

方面级别情感分析之四元组预测

情感四元组预测现有方法 阅读本文之前我们默认你对情感分析有基本的认识。 如果没有请阅读文章(https://tech.tcl.com/post/646efb5b4ba0e7a6a2da6476) 情感分析四元组预测涉及四个情感元素: 方面术语a&#xff0c;意见术语(也叫观点术语)o&#xff0c; 方面类别ac&#xff0c…

0基础学习VR全景平台篇 第93篇:智慧景区教程

一、上传素材 1.上传全景素材 第一步&#xff1a;进入【素材管理】 第二步&#xff1a;选择【全景图智慧景区】分类 第三步&#xff1a;选择相对景区作品分组&#xff0c;上传全景素材 2.素材标注 第一步&#xff1a;选择上传成功后素材&#xff0c;点击【未标注】 第二步&…