在布局优化中,Androi的官方提到了这三种布局<include />、<merge />、<ViewStub />,并介绍了这三种布局各有的优势,下面也是简单说一下他们的优势,以及怎么使用。

include标签:实现布局重用

<include />标签能够重用布局文件,以下为标题栏的layout文件
titlebar.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="”match_parent”"
    android:layout_height="wrap_content"
    android:background="@color/titlebar_bg" >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="http://4265337.blog.163.com/blog/@drawable/gafricalogo" />
    ...
</FrameLayout>  

我们可使用Include标记重用这个文件,如下,titlebar.xml文件中的内容就被完全嵌入到了include所指定的位置。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="”match_parent”"
    android:layout_height="”match_parent”"
    android:gravity="center_horizontal"
    android:orientation="vertical" >
    <include layout="@layout/titlebar" />
    <TextView
        android:layout_width="”match_parent”"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    ...
</LinearLayout>  

注意:
  • 使用时还可以对include所引用内容的属性进行更改,也可以增加其他属性。
  • 若include标签指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖。
  • 在include标签中所有的 android:layout_* 都是有效的,前提是必须要写layout_width和layout_height两个属性。
  • 我们可以直接通过findViewById获取到include内部的组件,但是当布局中包含多个相同的include标签时,直接的方式只能获取到第一个include的内部组件,因此,此种情况下若想获取指定include的内部组件,需使用间接方法:
    View view = findViewById(R.id. include标签的id).findViewById(R.id.include标签内部组件的id);
注意:
  • 若在RelativeLayout中使用include标签后,发现include进来的控件无法用layout_alignParentBottom="true"等标签来调整,可以在include的时候重载下layout_width和layout_height这两个标签。因为如果不重载,任何针对include的layout调整都是无效的!
包青天个人理解:
  • include标记的作用和自定义组合控件的作用是基本一致的,区别可能是:自定义组合控件只是提供了基本的样式,而在使用时常常需要对View样式或内容进行修改(通过暴露的set,get方法或自定义属性),而使用include是为了完全复用View,对样式或内容都不要任何修改(当然也可以通过覆盖一些属性达到修改的目的,但这样很不友好),最多只是修改设置ID、布局位置等信息。

marga标签:减少布局嵌套

上面的include适用于在某个布局内部引入某个可复用的布局的情况,但有一个副作用就是他多套了一层root节点,使得再构图的时候会多花费了一点时间。例如上例的 titlebar.xml,我本来只是想复用ImageView的,现在不得不将他的父布局 FrameLayout 也引进来了(当然,如果复用的布局里只有一个控件,是可以不用layout直接将此控件作为root节点的,但是若只有一个控件,还搞什么复用呢,复用就是复用组合控件的)。
这时就可以使用merge标签解决这个问题。<merge/>标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。
如:titlebar2.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="http://4265337.blog.163.com/blog/@drawable/gafricalogo" />
     ...
</merge>  

merge标记可以直接设为root节点,这样形成的titlebar2文件就少了外层的FrameLayout节点,当titlebar2被include到文件中时,merge标记就会被忽略掉,而直接由里面的ImageView取代原来include的位置,避免了冗余的layout。


merge标签还有另外一个用途,例如在自定义组合控件时,我们一般都是定义一个类继承*Layout,然后将一个设置好的布局通过inflate()填充进去,如下:
public class PKView extends LinearLayout {
    ……
    inflate(mContext, R.layout.*, this);
}
为了减少布局冗余的情况,布局文件R.layout.*同样可以使用merge作为root节点。

注意:
如上例,root节点设置为merge标签后在xml中就不能再使用LinearLayout的属性,如orientation属性,若想设置此属性,需要在代码中进行设置。
如:this.setOrientation(LinearLayout.HORIZONTAL);
而对于其他通用属性,如:this.setBackgroundColor(getResources().getColor(R.color.transparent));
则在布局中设置就行了

注意:
  • 由上可知,include和merge是配合使用的,不是一个互斥的或者说是平级的关系。
包青天个人理解:
  • merge标记的作用并不是布局复用,而是解决布局没必要的层层嵌套的,不过由于merge常和include共同使用,所以才常说他们都是为了重用布局而设计的。

ViewStub标签:动态加载布局

在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。
 
        推荐的做法是使用android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所指向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。


<ViewStub />标签使用如下:
<ViewStub
    android:id="@+id/vs"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:layout="@layout/titlebar" />

当你想加载布局时,可以使用.setVisibility(View.VISIBLE) 或.inflate();方法。
当调用inflate()的时候,ViewStub将被其所引用的布局替代,并且返回引用的布局(如本例中返回的是FrameLayout)。
如上面的示例:
        ViewStub vs = (ViewStub) findViewById(R.id.vs);
        FrameLayout fl = (FrameLayout) vs.inflate();  
上面两行代码等价于:
        FrameLayout fl = (FrameLayout) (((ViewStub) findViewById(R.id.vs)).inflate());  

ViewStub的特点:
  • 1、在程序的运行期间,ViewStub只能Inflate一次,再次Inflate会报IllegalStateException。
     
  • 2、所以某个布局在Inflate后,就不会再有变化,除非重新启动。
    按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了,所以他不适合用于多次显示隐藏控件的场合。
  • 3、当然此后他仍可通过setVisibility方法控制布局是否显示,但性能优化之说就没有了
  • 4、想要控制显示与隐藏的只能是一个布局文件,而不能是一个View。
    当然若真想用也可以把View写在某个布局文件中。
注意:
  • 以下操作顺序是不允许的:
        先 vs.setVisibility(View.INVISIBLE); 或 vs.setVisibility(View.VISIBLE); 再 vs.inflate();
        先 vs.inflate(); 之后再 vs.inflate();
  • 以下操作顺序是允许的:
        先 vs.setVisibility(View.GONE); 再 vs.inflate();
        先 vs.inflate(); 再各种 vs.setVisibility(View.*)
  • 某些布局属性要加在ViewStub上而不是所引用的布局上面才会起作用,比如android:layout_margin*系列属性,如果加在FrameLayou或其子控件上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub中设置的属性在inflate()后会都传给(覆盖)相应的布局。

布局重用 include merge ViewStub的更多相关文章

  1. include的用法例子,以及include+merge的用法例子

    [include+LinearLayout]的使用例子 AndroidIncludeLayout.java package com.AndroidIncludeLayout; import andro ...

  2. 我的Android进阶之旅------>Android中的布局优化 include、merge 、ViewStub

    1.如何重用布局文件? 可以使用<include>标签引用其他的布局文件,并用android:id属性覆盖被引用布局文件中顶层节点的android:id属性值.代码如下: <!--引 ...

  3. 布局优化: <include />、<merge /> 、<ViewStub /> 标签的使用

    在布局优化中,Androi的官方提到了这三种布局<include />.<merge />.<ViewStub />,并介绍了这三种布局各有的优势,下面也是简单说一 ...

  4. Android性能优化:布局优化 详细解析(含<include>、<ViewStub>、<merge>讲解 )

    1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如何影响性能 布局影响Android性能的实质:页面的测量 & 绘制时间 1个页面通过递归 完成测量 & ...

  5. [Android]Android布局优化之 merge

    转载请标明:转载于http://www.cnblogs.com/Liuyt-61/p/6602915.html -------------------------------------------- ...

  6. Android手势识别 Camera 预览界面上显示文字 布局注意事项(merge布局)

    通常在Surfaceview作为预览视频帧的载体,有时需在上面显示提示文字.曾经我弄的都好好的.今天忽然发现叠加的TextView不管咋弄都出不来文字了,跟Surfaceview一起放在FrameLa ...

  7. Android的Databinding-需要使用控件id,listener以及布局有include的场景

    主的布局xml文件: <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bin ...

  8. 浅聊标签<include>和<viewStub>

    在开发中我们往往会遇到这种情况,当一个布局文件比较复杂时,我们一个劲地往里面拖各种控件button,textView,imageView阿等等,等过了一段时间后,出现bug,自己都把自己搞懵比啦,特别 ...

  9. xml布局中include的使用

    参考:http://blog.csdn.net/harvic880925/article/details/17263275 include_button1.xml <?xml version=& ...

随机推荐

  1. LightOJ_1248 Dice (III)

    题目链接 题意: 给一个质地均匀的n的骰子, 求投掷出所有点数至少一次的期望次数. 思路: 这就是一个经典的邮票收集问题(Coupon Collector Problem). 投掷出第一个未出现的点数 ...

  2. Java操作Oracle数据库以及调用存储过程

    操作Oracle数据库 publicclass DBConnection {     //jdbc:oracle:thin:@localhost:1521:orcl     publicstaticf ...

  3. golang入门-- 一个2D的图形库学习

    此库叫gg,源码在github. 1.获取源码并安装到本地: 首先要安装git (传送门)  :   https://git-scm.com/download/ 然后就可以通过  go get 命令从 ...

  4. 安卓天天练练(四)drawable state 属性

    今天又作茧自缚(item 写成 itme ╮(╯▽╰)╭ elipse还自动闭合了标签,来回查查查看报错,为啥点击无效呢!) 真欠抽,怪不得上班地铁上被个sb踢到脚趾头(目测有可能是同家公司的..同站 ...

  5. struts2 集成webservice 的方法

    由于项目需求的需要,要在原来用Struts2的框架之上集成webservice,因为之前单单做webservice的时候没有多大问题,使用 Spring 和 Xfire就可以轻松地发布服务,但是,当和 ...

  6. android--使用Struts2服务端与android交互

    一,服务器端: web.xml文件: <?xml version="1.0" encoding="UTF-8"?> <web-app vers ...

  7. Java实现字符串反转

    替换原则:index k 的值和 n-k 的值进行交换.(始终记住程序员的n.k都是字符串的实际位置.) 乘除的最基本实现还是来源于移位操作. public String reverse(String ...

  8. stringstream 与空格 (大家讨论一下代码结果的原因)

    #include <iostream> // std::cout, std::endl #include <iomanip> // std::setw #include < ...

  9. 在MacOSX下用管理员权限打开App应用程序

    最近但疼的事情比较多,特别是升级了10.9以后. 难怪10.9会免费,它喵的当我们所有人都是测试开发者,那我们做实验,到处都是BUG...虽然是这么吐槽了,但是实际上也没有特别大的,能够影响到我的生活 ...

  10. mac下的改装人生——关于机械键盘

    这几天好像弄了很多关于机械键盘的东西,我自己的这块键盘也已经慢慢熟悉了,感觉打字超级爽哈,然后看了很多网上关于机械键盘的帖子,也看了很多教程,在Amazon和Taobao看了很多键盘的价位,前几天还试 ...