[TOC]
# 布局优化
布局优化的思想很简单,就是尽量减少布局文件的层级。主要从以下几个方面入手:
* 善于重用布局文件
* 使用ViewStub仅在需要时才加载
* 删除无用的控件和布局
* 使用性能较好的ViewGroup
## 重用布局文件
### \标签
\标签可以允许在一个布局当中引入另外一个布局,那么比如说我们程序的所有界面都有一个公共的部分,这个时候最好的做法就是将这个公共的部分提取到一个独立的布局文件当中,然后在每个界面的布局文件当中来引用这个公共的布局。
```xml
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="@layout/titlebar" />
......
```
其中,在\标签当中,我们是可以覆写所有layout属性的,即include中指定的layout属性将会覆盖掉titlebar中指定的layout属性。
我们可以覆写titlebar中的任何一个layout属性,如layout_gravity、layout_margin等,而非layout属性则无法在\标签当中进行覆写。需要注意的是,如果想要在\标签当中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写效果将不会生效。
### \标签
\标签是作为\标签的一种辅助扩展来使用的,它的主要作用是为了防止在引用布局文件时产生多余的布局嵌套。
比如说我们需要编写一个确定取消按钮的公共布局,这样任何一个界面需要确定和取消功能时就不用再单独编写了,新建ok\_cancel\_layout.xml,代码如下所示:
```xml
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:id="@+id/ok"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="OK" />
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:text="Cancel" />
```
但是把这个布局文件通过\标签引入时,会造成布局嵌套,也就是又多了一层LinearLayout。布局层次如下:
![](https://img.kancloud.cn/a6/ed/a6ede73d13ac679be1b6d38d1683aca7_545x146.png)
使用\标签可以解决这个问题:
```xml
android:id="@+id/ok"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="OK" />
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:text="Cancel" />
```
此时布局层次如下:
![](https://img.kancloud.cn/a8/17/a8173fd5339d082004061db150a5720a_507x140.png)
## ViewStub仅在需要时才加载
有的时候我们会遇到这样的场景,就是某个布局当中的元素非常多,但并不是所有元素都一起显示出来的,而是普通情况下只显示部分常用的元素,而那些不常用的元素只有在用户进行特定操作的情况下才会显示出来。
Android为此提供了一种非常轻量级的控件:ViewStub。ViewStub虽说也是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低,将它放置在布局当中基本可以认为是完全不会影响性能的。
ViewStub 的使用很简单,在布局文件中像引入其他控件一样引入 ViewStub:
```xml
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />
```
需要展示 ViewStub 所引用的视图时,通过 id 获取到 ViewStub:
```java
ViewStub stub = (ViewStub) findViewById(R.id.stub);
View inflated = stub.inflate();
// stub.setVisibility(View.VISIBLE);
```
除了调用 inflate 方法,还可以调用 setVisible 方法来展示 ViewStub 所引用的 View。
关于ViewStub的使用,可以参考[ViewStub源码分析](http://wiki.xuchongyang.com/1262571)
## 使用性能较好的ViewGroup
* 删除无用的控件和层级
* 不需要嵌套时优先使用LinearLayout和FrameLayout,需要嵌套或者复杂布局时使用ConstraintLayout代替RelativeLayout
* LinearLayout、RelativeLayout、FrameLayout、ConstraintLayout几种布局的区别
* RelativeLayout 子 View 的排列方式是基于彼此的依赖关系,所以在测量时会在横向和纵向上分别测量一次
* LinearLayout 为线性排列,在没有设置 weight 属性时只测量一次,设置了 weight 属性也是测量两次
* FrameLayout会默认把所有控件摆放在布局的左上角,并覆盖在前一控件的上层,当然可以通过 layout\_gravity 属性来指定对齐方式
* ConstraintLayout 使用约束的方式来指定各个控件的位置和关系,View 的位置受到三类约束:其他 View、父容器、基准线,并且支持设置比例。可以使布局完全扁平化,性能更高
# 参考
《Android开发艺术探索》任玉刚 著