在今年,2016年的Google i/o 大会上,Google推出了Android studio2.2,其中包含了为Android界面布局推出的最新的约束型布局ConstraintLayout,接触过iOS界面开发的朋友,可以认为这是Google为Android推出的AutoLayout布局。因为这方面的资料还不是很多,大部分的资料都是Google官方介绍翻译,没有具体用在项目里的实例,在此正好公司项目中遇到一个问题,用ConstraintLayout解决了,期间也遇到点困难。在这里我写出来,希望可以帮助到大家,也为了推广这种布局,希望大家可以使用。
如图,需求是一个时间轴控件,使用ListView实现。
每个adapter中包含:
- 一个ImageView,表示时间轴中的进度点
- 进度点,上面的线line_top(View)
- 进度点,下面的线line_bottom(View)
- 两个TextView,分别是进度说明,和时间
- 一条横向的线line(View)
最终做出来的效果图如下
现在我们分析一下这个效果图:
- 进度点有两种形态,大小不一;
- 两个进度点之间的连线颜色可以改变;
- 进度点,上下的两条线,3个控件需要中心对齐;
- 进度点需要跟第一个的TextView第一行水平对齐,说明上半部分线高度可以固定;
- 第一个TextView行数不确定,说明下半部分线长度不确定;
- 横向的虚线左端与两个TextView保持在同一Y轴上,同时右端顶到屏幕最右边。
上面这6点是布局中需要注意的,不变的部分很容易,我们只需要关注变的部分,再精减一下:
- 进度点下面的线高度,可变;
- 第一个TextView行数,可变;
- 横向的灰色线长度要随着设备宽度变化;
再剖析一下,上面3点中,2,3两点很容易在RelativeLayout中实现,但是1的高度,是根据TextView的行高来实现的,既1的变化,依据2的变化。
可惜的是,我在用RelativeLayout,实现这3点的时候,发现下部的线高度不能自动保持跟第一个TextView,一样的高度,只能保持一行的高度,个人认为是TextView调用setText()方法时,通知了TextView的重新绘制,但是下部分的线没有重新绘制,这也许是RelativeLayout的不足之处。个人愚见,还有待探究。
因为我想用xml就把布局关系完成,不需要再代码里面在操作布局关系,通知绘制,所以就想到了新布局,ConstraintLayout约束布局。
下面开始:
第一步:创建布局,摆放控件
转换成为ContraintLayout
把需要的控件都放进去,如下图,大概摆好
现在我们看到的大概的位置,没有添加任何约束。
第二部:添加约束
对于约束,每一个控件至少水平方向,垂直方向各有一个约束,才能使视图不会报错,想让自己的布局完美展现在手机上,我们应该消除所有警报。
首先我们知道line_top位置和长度都是固定的,这里我让它距离屏幕左边30dp,高度设置为12dp。鼠标放在line_top上,会出现4个空心圈。这4个空心圈代表着line_top,上下左右都没有设置约束,我们想让line_top距离左边30dp,鼠标点击左边的空心圈,按住不松,拖至屏幕左边沿,会出现如下图,松开就设置了一个约束,
这时我们观察,界面左边栏。如下图:
按照上面的操作,再把line_top上方设置一个约束,距离顶部0dp。这样line_top这条线就被固定住了。
现在我们之后所有的控件都直接依赖或者间接依赖这个line_top控件,进行布局。
下面我们将进度点ImageView这个控件,与line_top中心对其,如下图:
ImageView左右两边都设置约束,分别对line_top左右两边对齐,这时进度点ImageView自动中心对齐了line_top。很简单,但是我一开始就想不到,也是试了半天才知道要这么设置。
这时,我们要开始布局下一个控件了么?不,我们应该检查刚刚的Imageview有没有满足下面这条准则:
对于约束,每一个控件至少水平方向,垂直方向各有一个约束,才能使视图不会报错,想让自己的布局完美展现在手机上,我们应该消除所有警报。
显然这个进度点在垂直放向缺少一个约束,我们让他上方距离line_top有3dp的距离
ok,此时我们设置下一个控件,第一个TextView,TextView上方与进度点ImageView上方水平对齐,�我们拉住TextView上方的空心圈,移到ImageView的上方,送手,就完成了水平对齐
再设置左边到ImageView右边距离为16dp。完成如下图:
接下来我们让第二个TextView完成它的约束,我就不细讲了,相信你们也明白怎么用了,如下图:
下面是重点了,line_bottom的约束我们怎么设置:
这里我们看到有两个约束,一个是左边与line_top左边对齐,这样因为line_top已经与ImageView中心对齐,所以line_bottom这样也会跟ImageView中心对齐,但是我们知道line_bottom长度不固定,是可变的。选中line_bottom,接下来,我们看下图:
如下3种模式:
显然我们要把它切换为AnySize。
再让line_bottom下方与横向line距离为0dp,完成约束,如下图:
最后我们只剩下一个横线line,没有设置约束了,一样他也是可变的,设置为AnySize,添加约束。如图:
完成了么?
看起来好像没有问题了。不过我们是不是忘了第一个TextView内容很多,可能会出现几行的情况。
这里我们还需要给第一个TextView的右边设置一个到屏幕右边沿的约束,我们设置为距离右边50dp,同时TextView的宽也要设置为AnySize,因为他是可变的。
最后所有约束设置完成,我们看一下完整版的图:
我们可以试验一下是否可以自动适应高度。我们向第一个TextView中写入一段话,将控件撑大点,效果如下图:
可以看到效果很不错。到此为止,解决问题,同时ConstraintLayout可以完成很复杂的布局,减少布局的层次,Android布局层次越深,带来的性能损耗越大,当然对于目前Android手机性能不是问题,但是作为一个进益求精的开发者,谁不希望用最少的资源,完成最酷的效果呢?