不知道从什么时候开始,创建的layout默认的layout是ConstraintLayout,一直不知道这是啥鬼东西,总是将其手动的改成LinearLayout,也就是说习惯了靠编写XML代码完成界面。偶然的一次机会,朋友推荐了一篇介绍ConstraintLayout的博客,一发不可收拾的出来了这篇博客。下面跟着我来了解ConstraintLayout。
后来了解到,ConstraintLayout是Android Studio 2.2中主要的新增功能之一,也是Google在去年的I/O大会上重点宣传的一个功能。在Android Stuido中有个可视化工具 - Layout Editor(布局编辑器),自从接触Android Studio以来(beat 0.6),它一直都存在,,鉴于种种原因,我们一直都是习惯于编写xml来完成界面。其最根本的原因还是视图的拖动,并不能完美的解决屏幕适配。
自从ConstLayout出现,我们可以放弃编写xml了,为什么呢?ConstraintLayout的所有功能都可以直接从可视化工具 - Layout Editor中实现,因为布局API和Layout Editor是专门为彼此构建的。因此,可以完全通过拖放使用ConstraintLayout来构建布局而不是编辑XML。
俗话说,工欲善其事必先利其器,接下来我们揭开Layout Editor的庐山真面目。
在”Design”选项中,如果没有选中任何视图,按着ctrl然后点击鼠标左键UI视图的任何位置,将会切换到Text;如果选中了某个视图,按着ctrol然后点击鼠标左键UI视图的任何位置,不仅会切换到Text,同时定位到选中的视图的code在XML的位置。
提示:您可以通过按 B 在这些视图之间进行切换。
“Attributes”窗口在顶部显示视图的inspector,位于src和contentDescription的视图属性上方。inspector显示UI元素的约束和边距,以及用于调整元素沿水平和垂直轴的位置偏差的进度条。
对于传统布局而言,比如说,RelativeLayout以控件之间相对位置或相对父容器位置进行排列,还有LinearLayout以控件之间的线性关系进行排列。传统布局完全可以完成任意界面,ConstraintLayout又有什么优势呢?
对于复杂的的布局,使用传统布局,我们最多的解决办法是各种嵌套,尽管有include可以使用,但并没有在根源上解决,除非这样的界面,通过自定义View来实现,又有点得不偿失。而,ConstraintLayout,即约束布局,可以在平面视图层次结构创建大而复杂的布局(无嵌套视图组),减少布局的层级, 优化渲染性能。它类似于RelativeLayout,因为所有视图都是根据兄弟视图和父容器之间的关系来布局的,但它比RelativeLayout更灵活,并且更易于与Android Studio的Layout Editor一起使用。至于,在ConstraintLayout中如何完成界面编写,后续讲解。
前面我们已经详细讲解了Layout Editor界面,了解到可以完全通过拖放使用ConstraintLayout来构建布局而不是编辑XML,这样大大的提高了编写界面的效率,这种优雅的的方式,后续展现。
在这里又有一个疑问,ConstraintLaytout对于低版本是否兼容呢?ConstraintLaytout本事是由support库来提供的,它可适用于与Android 2.3(API级别9)及更高版本兼容的API库。当然,要使用ConstraintLayout,首先需要在app/build.gradle文件中添加ConstraintLayout的依赖:
dependencies {
...
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
美中不足的是,它对buildTools还有一定的要求,必须在25.0.3以上。如果配置低的话,升级下即可。
buildToolsVersion "25.0.3"
在ConstraintLaytout中,如果要指定视图的位置,必须为视图添加至少一个水平和一个垂直约束。这里又提到了约束的概念,约束表示与另一个视图,父布局或不可见的guideline连接或对齐。约束不难理解,把视图放在ConstraintLaytout中,如果想要确定视图的位置,必须提供一个位置的相对关系,不管使用坐标系还是相对关系。这里,我们先了解到约束的作用就是用来在ConstraintLaytout中,限定视图位置的。
接下来,我们在ConstraintLaytout中完成界面。首先要知道的是如何创建一个ConstraintLaytout?
如果Android Studio自动默认创建的是传统布局,比如RelativeLayout,我们可以通过如下操作将它转换成ConstraintLayout。
要创建新的ConstraintLayout文件,按照下列步骤操作:
如果想为视图添加约束,首先将视图从“Palette”窗口拖动到Layout Editor中。当在ConstraintLayout中添加视图时,它会在每个角上显示一个带有方形调整大小控键的边框,并在每边显示圆形约束控键。
点击视图以选择它。 然后单击并按住其中一个约束控键并将该行拖动到可用的锚点(另一个视图的边缘,父布局的边缘或GuideLine)。当释放时,将添加约束,默认边距分隔两个视图。这里,我们将一个Button的左侧面约束到父容器的的左侧:
这样,我们就为Button创建了一个约束。
可是,如上图,仔细看Layout Editor,有个标志,点开后提示:大概意思是,Button缺少垂直约束,在运行后,其将在布局的左边。我们来看看约束的规则:
这也就是说,对于Button的约束而言,因为缺少了垂直约束,Layout Editor则会给出错误提示。尽管缺少的约束不会导致编译错误,但是会导致界面不能按照我们预想的显示。以后,我们在为视图添加约束时,尤其要注意Layout Editor的提示,查看是否是否有缺少约束。为了避免缺少约束,Layout Editor可以使用自动连接(Autoconnect)和infer约束功能以便自动添加约束,至于这两种添加约束的方式,是否可行,后续再说。
将视图的一边约束到布局的相应边缘。
在下图中,将视图的左侧连接到父容器的左边缘。 可以定义边缘与边距的距离。
在前面,我们已经知道如何给视图添加约束。现在,我们将通过约束来指定视图的位置。在ConstraintLayout中,Relative positioning,即相对位置是创建布局的基本构建模块之一。它类似RelativeLayout的layout_toLeftOf、alignParentLeft等这些属性。这些约束用来指定给定的控件相对于另一个控件的位置,可以在水平和竖直方向约束控件。
通常,将一个控件的约束边位于任何其他控件的另一侧。
例如:将按钮B放在按钮A的右边:
如果
我么可以这么做:
上述代码,告诉我们,按钮B的左边被约束到按钮A的右侧,表示按钮B与按钮的A的右侧对齐。
在ConstraintLayout中,定义了一系列的相对位置的约束属性,它们都将引用一个控件id,可以是任何其他视图,也可以是父容器(即引用父容器,即ConstraintLayout),表示视图的某侧被约束到指定视图/父容器的某侧。约束属性列表如下
刚才在设置按钮的B的约束是在xml里面设置的,前面已经提到了可以在Layout Editor里面通过拖动设置约束,我们可以这么做:
这样,就不用再xml一行行的码代码了,只要拖动就好了,爽的要不得。。。
在ToolBar中,曾提到一个工具 Autoconnect,它是用来设置是否自动设置约束。如果将自动设置约束打卡,自动连接可以为父容器的视图元素创建两个或多个约束(因为一个视图最少有一个横向和一个竖向约束)。 将视图拖动到布局之后,它将基于元素的位置创建约束。
约束被自动添加到视图的所有四面,我们可以看到ImageView位于Layout的中心,这是为何?让我们来看xml是如何定义的:
从xml中可以看出,layout_constraintLeft_toLeftOf和layout_constraintRight_toRightOf是两个完全相反的约束。在ConstraintLayout中,如果在视图中添加两个相反的约束,则像弹簧一样,约束变得像一个弹簧一样表示相反的力。当视图大小设置为“fixed”或“wrap_content”时,效果最为明显.在这种情况下,视图以约束为中心。同样的,layout_constraintBottom_toBottomOf和layout_constraintTop_toTopOf也是两个完全相反的约束。这也不难解释为什么ImageView位于Layout的中心了。
当ConstraintLayout里面的视图过多时,总避免不了一时手抖,或者其他原因,导致约束链接错误。我们该如何删除错误的约束呢?
让我们来看上面的界面,其中一个明显的特点就是不同视图之间的对齐。UI在设计界面时,为了让界面更简洁,视图的对齐,肯定是一个优雅的处理方式之一。那么问题就来了,在ConstraintLayout该如何对齐呢?我们先了解对齐的概念,对齐就是将视图的边缘对齐另一个视图的相同边缘,或者是视图的中心对齐另一个视图的中心。
在上图图中,B的左侧与A的左侧对齐,我们只需要将B左侧约束到A的左侧即可:
刚才,只是将两个视图的一侧对齐了,如果想两个视图的中心对齐,应该怎么做呢?前面,我们提到过两个相反约束的作用,这里可以试一下,在两个视图的两边都创建约束:
对于,在视图两边创建约束,视图对齐中心的原因这里不多描述,不了解可以看下前面对于两个相反约束的作用解释。
刚才只是,做了两个视图的对齐,如果是多个视图对齐,是不是就需要两两作对分别做约束呢,不用说也是特别的繁琐,必然不合理。既然不合理,那不用说也有工具了。在工具栏 7的作用是设置对齐方式。那么我们可以这么做
选择需要对齐的视图
通过工具栏选择对齐方式
下面,我们在在Component Tree中选择所需对齐的视图,然后在Component Tree里右键点击被选择的视图,在Align中选择视图中心对齐:
不管是英语还是其他语言(汉语除外),为了规范书写会设有四条线,从上至下第三条就是基线,以保证书写更整齐。如下所示:
对于文本视图而言,例如TextView,EditText或Button,以使文本基线对齐,也为此设置了BaseLine相关属性,比如,RalativeLayout中的android:layout_alignBaseline属性用于设置当前组件与参照组件的基线对齐,或者是LinearLayout中的android:baselineAligned属性用于设置是否允许用户调整它内容的基线。关于传统布局的基线对齐,这里不多描述。我们还是关心ConstraintLayout中的文本视图的基线对齐。在ConstraintLayout中,使用基线约束来对齐使用不同文本大小的视图。即使视图中的文本元素大小不一,依然可以使用基线约束来对齐元素。这里我们来做个输入账号的界面:
单击TextView“id”元素并将其指针悬停在其上。元素下方出现基线对齐的ab按钮,因为元素中包含文本:
单击ab按钮显示文本基线。然后从TextView“id”的基线(绿色闪烁)中单击并拖动到lain Tex的基线,如下图所示:
如果两个视图中的文本是多行,而且文本大小不一时,通过基线约束对齐,具体效果见下图:
从上图中,我们可以清晰的看到:
这里,先说说GuideLine是什么鬼。Guideline是ConstraintLayout的Guideline辅助对象的实用程序类,该辅助对象不会显示在设备上,它被默认是View.GONE,而且不可改。另外,Guideline是专门为ConstraintLayout创建的,也就是它仅也只能用于ConstraintLayou布局。
Guideline可以是水平或垂直的:
GuideLine也可以认为是视图,其可以根据相对于布局边缘的dp或百分比,将GuideLine定位在布局中,位置确定有三种方式:
如果你想创建一个GuideLine,可以点击工具栏的,然后在弹出框中选择水平的还是垂直的:
在创建GuideLine以后,其默认的位置确认方式是layout_constraintGuide_begin,我们可以拖动虚线来重新指定它的位置。如果你想改变它的定位方式,单击GuideLine边缘的圆圈以切换测量模式。如下图所示。
对于GuideLine的情况先说到这,接下来我们来了解Guideline有什么用?下面这个图,是登录界面一部分,可以清楚看出来,布局左右两边的pading是44dp。
现在,我们创建一个GuideLine,其layout_constraintGuide_begin的值为44dp,然后把TextView(”账号”和密码)约束到GuideLine:
到这里,我们知道GuideLine其实就是一种约束规则,供其他视图使用,以统一处理距离ConstraintLayout边缘的距离,而不用单独处理约束偏差。
对于GuideLine有个不解的地方,先看下面一段代码:
如上述代码所示,一个Button的左右两侧约束到两个垂直GuideLine,其width类型为wrap_content。如果Button中文本的长度超过两个GuideLine之间的距离时,Button本事会超过GuideLine的边界。如果将width类型为fixed,并指定其宽度大于两个GuideLine之间的距离时,依然如此。这样,必然会造成视图被覆盖的现象。
如果将width类型修改为MATCH_CONSTRAINT,效果是这样的:
造成这种问题的根本原因在于ConstraintLayout对于空间的计算方式。早在ConstraintLayout 1.0.2版本以前,有barriers用来协助约束,但是在1.0.2已经取消了这个辅助类。在这种情况下,是将width类型修设置为MATCH_CONSTRAINT还是限制文本显示的内容,这是我们值得考虑的问题。
本来打算一篇写完的,后来发现添加图片过多,导致篇幅很长,那就先说到这里,后续再写。到这里,本文主要介绍了Layout Editor的相关界面及在ConstraintLayoput中如何定位视图、对齐视图等。接下来,将了解如何修改视图的属性?如何处理带有链的线性视图组?