当前位置:

首页 > 系统应用 > 10.8 LayoutInflater(布局服务)

10.8 LayoutInflater(布局服务)

本文目录

    本节引言: 本节接着来看 Android 系统服务里的 LayoutInflater(布局服务)。一提到“布局”,很多人脑子里第一反应通常都是:先写好一个布局 xml,再通过 Activity 的 setContentView() 把它加载进来,最后显示到屏幕上。这个理解没错,不过再往底层看一层,会

    本节引言:

     本节接着来看 Android 系统服务里的 LayoutInflater(布局服务)。一提到“布局”,很多人脑子里第一反应通常都是:先写好一个布局 xml,再通过 Activity 的 setContentView() 把它加载进来,最后显示到屏幕上。这个理解没错,不过再往底层看一层,会发现背后真正干活的,其实还是 LayoutInflater,它依赖的是 Android 内置的 Pull 解析器来完成布局解析。平时在 Android 开发里,只要涉及动态加载布局,或者运行时添加控件,LayoutInflater 都会频繁出现。接下来,就顺着实际开发场景,把它的常见用法捋一遍。

    官方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.纯Ja va代码加载布局

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

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

    纯Ja va代码加载布局的流程:

    ——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 sa vedInstanceState) {  
            super.onCreate(sa vedInstanceState);  
            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.Ja va代码动态添加控件或xml布局

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

    1)Ja va代码动态增加View

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

    先写个布局文件先:activity_main.xml:

      
      
      

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

    public class MainActivity extends Activity {  
        @Override  
        protected void onCreate(Bundle sa vedInstanceState) {  
            super.onCreate(sa vedInstanceState);  
            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 sa vedInstanceState) {  
            super.onCreate(sa vedInstanceState);  
            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)Ja va代码动态加载xml布局

    接下来的话,我们换一个,这次加载的是xml文件!动态地添加xml文件! 先写下主布局文件和动态加载的布局文件:

    activity_main.xml:

    
        

    inflate.xml:

      
      
      
    

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

    public class MainActivity extends Activity {  
        @Override  
        protected void onCreate(Bundle sa vedInstanceState) {  
            super.onCreate(sa vedInstanceState);  
            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;    
        }    
    } 

    本节小结:

    本节给大家讲解了一下Android中的LayoutInflater(布局服务),以及动态加载View和控件 相关的东西,相信对初学控件的朋友带来帮助~好的,就说这么多,谢谢~

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    系统应用 浏览器
    相关文章 更多
    docker容器自动重启怎么解决 排查原因与修复方法
    docker容器自动重启怎么解决 排查原因与修复方法

    遇到Docker容器频繁自动重启?本文提供从查看容器日志、解读退出代码到配置Restart Policy的完整排查与修复方案,确保服务稳定性。

    Linux设置静态路由命令与永久生效教程
    Linux设置静态路由命令与永久生效教程

    学习如何在Linux中使用命令行添加临时静态路由,并通过修改网络配置文件实现重启后依然有效的永久静态路由设置,涵盖CentOS和Ubuntu的不同配置方法。

    摄像头连接电脑后怎么打开查看实时画面教程
    摄像头连接电脑后怎么打开查看实时画面教程

    摄像头连接电脑后不知如何查看画面?本教程演示如何使用Windows自带的“相机”应用快速调取实时视频流,无需下载额外软件,步骤简单直观,适用于大多数USB及内置摄像头。

    如何在 windows 11 关闭自动关机
    如何在 windows 11 关闭自动关机

    针对 Windows 11 电脑在无人操作时自动关机或重启的问题,本文详解如何通过任务计划程序禁用更新重启任务,并调整电源睡眠策略,从根源解决非预期的自动关机现象。

    电脑摄像头怎么测试人脸识别功能及效果判断方法
    电脑摄像头怎么测试人脸识别功能及效果判断方法

    详细讲解在Windows电脑上测试摄像头人脸识别功能的步骤,包括开启Windows Hello、录入面部数据、不同环境下的效果验证及常见问题排查,帮助用户确认设备兼容性与识别准确率。

    docker 容器无法启动的配置检查命令及排查方法
    docker 容器无法启动的配置检查命令及排查方法

    当 Docker 容器启动后立即退出时,不要盲目重启。本文详解如何通过 docker logs 查看标准输出错误,利用 docker inspect 检查挂载与网络配置,并修正入口点脚本权限问题,提供一套高效的因果排查流程。

    安卓手机投屏到电脑win10怎么设置教程
    安卓手机投屏到电脑win10怎么设置教程

    详解如何利用Windows 10自带功能将安卓手机画面投射至电脑屏幕,涵盖开启步骤、连接技巧及延迟分析,适合临时演示与多屏协作场景。

    移动硬盘解除加密怎么操作?详细步骤教程
    移动硬盘解除加密怎么操作?详细步骤教程

    详细介绍如何在Windows系统中为移动硬盘解除BitLocker加密,包括解锁驱动器、关闭加密功能及监控解密进度的完整操作流程,帮助用户安全移除数据保护。

    笔记本电脑耳机没声音怎么设置?Windows 10解决方法
    笔记本电脑耳机没声音怎么设置?Windows 10解决方法

    本文详解Windows 10笔记本耳机无声音的常见原因与解决方法,涵盖物理接口检查、默认播放设备切换、驱动程序更新及音频增强关闭等操作,并分析蓝牙耳机连接异常的例外场景。

    sata固态硬盘安装win10系统怎么分区详细教程
    sata固态硬盘安装win10系统怎么分区详细教程

    还在为SATA固态硬盘装Win10怎么分区头疼?本教程详解安装过程中的分区步骤,涵盖4K对齐检查、ESP引导分区处理及容量规划建议,助你一次性搞定系统盘,避免后期卡顿与空间浪费。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    赤友清理大师
    赤友清理大师
    macOS

    赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

    WINDOWS 更多
    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    Windows 10
    Windows 10
    Windows

    Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

    极度公式
    极度公式
    Windows/macOS/Linux

    极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。