本文涉及到的知识点
- 简单的说明以下布局优化的重要性
- 一些布局使用的注意事项
- include、merge与ViewStub的使用
- ConstraintLayout的使用
1.布局优化的重要性
GPU过度绘制参考图在日常开发中对于布局我们很少注重性能,主要注重的就是相应的展示问题。可能由于界面的复杂程度,使得界面嵌套的层级过多,这样也就导致了绘制页面的卡顿现象。增加了GPU渲染的复杂程度。这里引用一张图片来说明相应的问题。
怎么查看呢?手机设置->开发者选项->调试GPU过度渲染 打开之后你就能看到你的APP到底有没有过度绘制了。如果你看见的是一片红,那么恭喜你...你必须考虑相应的优化了!说了这么多,其实最重要的就是减少层级、减少相应的过度绘制,就能有效的对布局进行相应的优化。所以在Android做一些简单的布局优化还是有必要的。。。
2.一些布局使用的注意事项
这里先提出个问题,大家想一下?如果项目中有这样一个需求,竖直排列两行每行两个元素,大家怎么去实现呢?相信有的人会使用相对布局,有的人会使用线性布局,那么问题就来了,如果你使用线性布局的话,就会存在布局嵌套的问题,就平白的多了一层布局嵌套,平时开发的时候这样的问题很多,如果你多加注意的话,你会发现很多这样的问题。
这里我主要想说的是,如果在平时开发布局的时候,如果在布局不是很复杂的情况下尽量使用相对布局,少用线性布局。但是大家要注意一点,如果布局复杂的话,或者层级较深的情况下,最好还是使用线性布局。这里不知道大家注意没有,在Android Studio2.+版本的时候,所有默认的布局都是线性布局,为什么呢?我就不在继续深入讲解了,感兴趣的同学可以看看尹star
的->Android中RelativeLayout和LinearLayout性能分析主要是Measure在测量的时候产生的性能消耗!所以这个问题主要看你布局是否比较复杂。。。其实在现在的版本中,google推荐我们使用的是ConstraintLayout(这个我会在后面详细的讲解)
3.include、merge与ViewStub的使用
说到布局优化问题,很难不提及include、merge与ViewStub的使用,但是这些都有相对的局限性的,下面我们就来一一讲解:
3.1 include的使用和注意事项
这个东西相信大家都不陌生,它能帮我们解决布局复用的问题,只要include导入一个布局就可以了。像这样:
<include layout="@layout/XXX"/>
XXX代表引入的布局。是不是很简单,那么我问大家几个问题?
- 如果在include标签中我设置相应的layoutxxx的属性,会对原来的布局有什么影响?
- 如果在include标签中我设置了id,会对原来的布局有什么影响?
这些问题,相信细心的人应该会有体会的,但是对于有些人来说,或许很陌生。所以这里有必要说明一下:
- 当你在include中设置layoutxxx属性的时候,会覆盖相应导入根布局的layoutxxx属性,怎么理解呢?也就是说如果你导入的布局是这样的
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#223344"
android:gravity="center"
android:text="导入的布局"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
这里看好,LinearLayout的宽和高是占用父窗体。如果你要是这么写
<include layout="@layout/test_view" />
的话,会显示全屏的,就像这个样子
没有设置layoutxxx的属性
但是如果你要是写成这个样子就不一样了
<include
layout="@layout/test_view"
android:layout_width="200dp"
android:layout_height="200dp" />
会变成这个样子
设置了layoutxxx的属性
这里要特别注意一下。。。
- 当你在include中设置id的时候,会覆盖相应导入根布局的id属性,也就是说你只能使用include中的id属性获取根view了!
3.2 merge的使用和注意事项
对于新手来说,这个标签应该很少使用,至少我是这样的,其实我呆了这么多公司,也很少有人去用这个,可能我呆的都是小公司吧!哈哈。。。不闲扯了,其实这个标签主要是针对include导入的标签的根布局来说的,可以减少一个层级的嵌套!
先来说一下这个怎么看啊!!!不说这个的都是扯淡。。。在Android Studio3.+版本上按照下图获取!
查看视图树的工具中间会弹出一个对话框,然后你就点确定,就能查看相应的视图树了。。。
- 当你没有使用merge标签的时候,布局是这个样子的!
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#223344"
android:gravity="center"
android:text="导入的布局"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
这个时候你查看一下视图树你会发现会出现下面这个样子。
未使用merge标签的视图层级我已经用红框画出来了,中间有一层LinearLayout作为根布局,但是如果你把上面的LinearLayout换成merge标签就不会有中间这层LinearLayout了。这个就不贴图了,不信的你可以试试。。。
还有一个问题需要注意:
这里有必要说明一下,如果你要给merge标签设置一些属性怎么办?其实是这样的,你可以根据include的父控件进行属性的设置,如果父控件是LinearLayout你就可以设置weidge或者相应LinearLayout的特有属性...这也充分说明了为什么include可以使用layoutxxx属性覆盖根布局的layoutxxx属性。
3.3 ViewStub的使用和注意事项
其实关于这个ViewStub这个标签,就相当于延时加载,但是有很多局限性,打个比方说吧!相应在平时开发的时候,都会根据状态进行一些控件的显示和隐藏吧,一般的处理都是View的setVisibility();但是这里如果你改变一次之后还能进行改变的话,那么就不能使用ViewStub这个标签。因为ViewStub对控件只有一次的改变,其实ViewStub在布局加载的时候已经加载出来了,只是宽和高都是0罢了,当你inflate()的时候,再去加载这个整体的View,达到了延迟加载的目的!
基本的写法就是这样,也是导入一个layout
<ViewStub
android:id="@+id/vs_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/test_view" />
什么时候你想加载了,就调用View inflate = mVs.inflate();
方法就能让这个View显示出来,但是一定要注意,这个方法只能使用一次,切记!切记!切记!重要的事情说三遍,当这个View加载出来的时候,你就可以像对待其他View对待它了,如果你要对这个View做一些特有控件的操作,最好强转一下。。。
基本上上面这三个View优化的标签我总结的就这么多,有什么不对的还请指出,我会立即改正的!!!
4. ConstraintLayout的使用
关于这个控件,其实google早在很早的时候就让我们去尝试着使用了,但是在1.0.2那个版本的时候(记不太清楚了)才作为根布局使用的。
A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.
Note: ConstraintLayout is available as a support library that you can use on Android systems starting with API level 9 (Gingerbread). As such, we are planning on enriching its API and capabilities over time. This documentation will reflect those changes.
这里面引用了google的解释,大概的意思是
ConstraintLayout继承ViewGroup允许您以灵活的方式定位和调整小部件的大小。
ConstraintLayout可用作支持库,您可以从API级别9(姜饼)开始在Android系统上使用该支持库。因此,我们计划在一段时间内丰富其API和功能。本文档将反映这些更改。
主要是约束内部控件位置的布局,里面包含关于相对位置的属性:
- layout_constraintLeft_toLeftOf 当前控件的左侧和目标控件的左侧对齐
- layout_constraintLeft_toRightOf 当前控件的左侧和目标控件的右侧对齐
- layout_constraintRight_toLeftOf
- layout_constraintRight_toRightOf
- layout_constraintTop_toTopOf
- layout_constraintTop_toBottomOf
- layout_constraintBottom_toTopOf
- layout_constraintBottom_toBottomOf
- layout_constraintStart_toEndOf
- layout_constraintStart_toStartOf
- layout_constraintEnd_toStartOf
- layout_constraintEnd_toEndOf
其实属性很多,估计让你记你也记不住,所以总结一下:
这里所有的都可以这么去理解,layout_xxxA_toxxxB 理解为,当前控件的A侧和目标控件的B侧对齐,你可能还是不理解,拿第一个举例说明下,就是当前控件的左侧和目标控件的左侧对齐,标记了两个,其他的以此类推。这里注意里面设置的参数是目标控件的id/父容器只有这两种可能!
如果你有两个控件,左侧的以父控件对齐,另一个控件以左侧的控件对齐,这时候如果右侧以父控件对齐的话,这个控件会在右侧剩下的空间居中(像下面这样),但是如果你要是不设置右侧的属性的话,那么两个会挨着!(是那个属性拆散了它们!哈哈)
- layout_constraintHorizontal_bias 水平偏差百分比
- layout_constraintVertical_bias 竖直偏差的百分比
这两个属性是针对于上面这个产生偏差的(只能设置以为小数,最大是1),其实我试过,只要你左右或者上下都有约束的时候,这个相应的属性才生效,否则是无效的(如:一个控件左右都有约束,那么设置layout_constraintHorizontal_bias才会生效,否则是不会生效的,竖直方向的同理)
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
如果你设置了相应的margin_xxx属性,那么主要是产生了相应的边距,和其他的控件都一样,这里就不再多做解释了.
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
这里说明一个问题,当你有一个View处于GONE的情况,其他View还以来这个View来进行布局,那么就需要设置上面的goneMarginXXX来设置相应的Margin(PS:这个只有在你依赖的那个约束为GONE的时候才会生效的属性)
- android:minWidth 设置布局的最小宽度
- android:minHeight 设置布局的最小高度
- android:maxWidth 设置布局的最大宽度
- android:maxHeight 设置布局的最大高度
这几个属性没有什么好说的了!
- layout_constraintDimensionRatio 设置宽高比
这个属性很有意思:设置相应的宽高比,但是我试了,至少要有三面有约束,否则不起作用,并且宽度和高度都应该设置成"0",参数值可以是"1:1"或者"h,1:1"也可以是"w,1:1"其中h代表限制高度,w代表限制宽度.这里的比例不管你前面是什么,后面的比值都是"宽度:高度"
- layout_constraintHorizontal_weight
- layout_constraintVertical_weight
这两个属性相当于LinearLayout的weight属性和LinearLayout的属性设置是一样的
- layout_constraintHorizontal_chainStyle
- layout_constraintVertical_chainStyle
- CHAIN_SPREAD 默认样式(如果某些小部件设置为MATCH_CONSTRAINT,则它们将拆分可用空间)
- CHAIN_SPREAD_INSIDE 但链条的终点不会被分散
- CHAIN_PACKED 链条的元素将被打包在一起。
这里我用的时候踩了一个大坑,这里所谓的链式,你必须确保从左至右或者从上至下多有的约束都连着,这里的连着是都有相应的约束:
如view a 和view b在竖直方向上形成锁链:a的属性设置为 top_toTopOf = “parent” bottom_toTopOf = “b” b的属性设置为top_toBottomOf=“a” bottom_toBottom = “parent"切记!切记!切记!都要连上....重要的事情说三遍,否则你是看不见效果的.效果就是上面这张图的效果!
这里使用了这个布局,就能减少布局的嵌套,也使得绘制的时候能减少GPU的负担,这样就能达到布局优化的目的了!!!
上面这些......基本上就是我在项目中优化布局时候所做的一些优化,有什么不妥的地方还请指正!
2018年04月18日补充
其实ConstraintLayout还有一个基线的定义,什么意思呢?就是当你布局没有参考点的时候,你可以设置一个相应的基线,然后其他的内容,都以这个基线为参考!像下面这样
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
这里有几个属性说明一下:
- orientation 代表方向性的
- layout_constraintGuide_percent 代表在父控件中的百分比
这样一个基线就完成了,完成之后其他的参考和上面的写法就都一样了。
欢迎关注我的公众号
网友评论