欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android ConstraintLayout图文并茂详解(一)

程序员文章站 2022-05-07 08:02:18
...

不知道从什么时候开始,创建的layout默认的layout是ConstraintLayout,一直不知道这是啥鬼东西,总是将其手动的改成LinearLayout,也就是说习惯了靠编写XML代码完成界面。偶然的一次机会,朋友推荐了一篇介绍ConstraintLayout的博客,一发不可收拾的出来了这篇博客。下面跟着我来了解ConstraintLayout。

LayoutEditor

后来了解到,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的庐山真面目。

Layout Editor全景

Android ConstraintLayout图文并茂详解(一)

  1. 工具栏(Toolbar):提供在编辑器中配置布局外观和编辑布局属性的按钮
  2. Palette:提供小部件和布局的列表,您可以将它们拖动到编辑器内的布局中
  3. Component Tree:显示布局的视图层次结构。在此处点击某个项目将看到它在编辑器中被选中
  4. 设计视图:用来显示界面
  5. blueprint视图:在该视图中可以清晰的看到布局相关信息,约束关系、边距等
  6. 属性(Attributes):针对当前选择的视图提供属性控件

Design和Text选项卡

  • Design:可以在LayoutEditor中配置布局的外观
  • Text :查看xml中的布局代码,同时在Preview窗口中查看当前界面显示

Android ConstraintLayout图文并茂详解(一)

在”Design”选项中,如果没有选中任何视图,按着ctrl然后点击鼠标左键UI视图的任何位置,将会切换到Text;如果选中了某个视图,按着ctrol然后点击鼠标左键UI视图的任何位置,不仅会切换到Text,同时定位到选中的视图的code在XML的位置。

更改预览外观

Android ConstraintLayout图文并茂详解(一)

  1. Design and blueprint:用于选择在编辑器中查看布局的方式。Design 视图显示布局的彩色预览,而 Blueprint 视图仅显示每个视图的轮廓。或者,您可以并排查看 Design + Blueprint 。
    提示:您可以通过按 B 在这些视图之间进行切换。
  2. Screen orientation:用于在横屏和竖屏方向之间旋转设备。
  3. Device type and size:用于选择设备类型(手机/平板电脑、Android TV 或 Android Wear)和屏幕配置(尺寸和密度)。您可以从多个预配置的设备类型和您自己的 AVD 定义中进行选择,或从列表中选择 Add Device Definition 新建 AVD 定义。
    提示:您可以通过拖动布局的右下角来调整设备尺寸。
  4. API version:用于选择要在上面预览布局的 Android 版本。
  5. App Theme:用于选择将应用到预览的 UI 主题背景。注:此按钮仅对支持的布局样式有效;因此,此列表中的许多主题背景会导致错误。
  6. Language:用于选择显示 UI 字符串的语言。此列表仅显示字符串资源中可用的语言。如果您要编辑译文,请从下拉菜单中点击 EditTranslations(请参阅使用 Translations Editor 对 UI 进行本地化)。
  7. Layout Variants:用于切换到此文件的一个备用布局,或创建一个新布局(请参阅下文的创建布局变体)。

视图的inspector

“Attributes”窗口在顶部显示视图的inspector,位于src和contentDescription的视图属性上方。inspector显示UI元素的约束和边距,以及用于调整元素沿水平和垂直轴的位置偏差的进度条。

Android ConstraintLayout图文并茂详解(一)

  1. hide:使用此按钮关闭“Attributes”窗口
  2. margin:通过单击值并选择不同的值来更改边距
  3. height/width类型:表示控件的宽度和长度
  4. Bias:使用进度来改变具有相反约束的元素的水平和垂直约束偏移
  5. 尺寸比(ratio):尺寸大小的比例
  6. 约束:表示当前侧面的约束,单击后可以删除约束

工具栏

Android ConstraintLayout图文并茂详解(一)

  1. Align:设置UI视图和blueprint视图中是否显示约束、边距等
  2. Autoconnect:设置是否自动设置约束
  3. 删除所有视图的约束
  4. 自动推断所有视图的约束
  5. 设置默认边距
  6. 设置视图填充可用空间
  7. 设置对齐方式
  8. 添加GuideLine

ConstraintLaytout概述

对于传统布局而言,比如说,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?

创建ConstraintLayout

转换布局

如果Android Studio自动默认创建的是传统布局,比如RelativeLayout,我们可以通过如下操作将它转换成ConstraintLayout。

  1. 在Android Studio中打开您的布局,然后单击编辑器窗口底部的“Design”选项卡。
  2. 在Component Tree窗口中,右键单击布局,然后单击“Convert layout to ConstraintLayout”。

Android ConstraintLayout图文并茂详解(一)

创建一个新的布局

要创建新的ConstraintLayout文件,按照下列步骤操作:

  1. 在Project窗口中,单击File > New > XML > Layout XML
  2. 输入布局文件的名称,并为根标记输入“android.support.constraint.ConstraintLayout”
  3. 点击“OK”

Android ConstraintLayout图文并茂详解(一)

为视图添加一个约束

如果想为视图添加约束,首先将视图从“Palette”窗口拖动到Layout Editor中。当在ConstraintLayout中添加视图时,它会在每个角上显示一个带有方形调整大小控键的边框,并在每边显示圆形约束控键。

Android ConstraintLayout图文并茂详解(一)

  • Android ConstraintLayout图文并茂详解(一)调整大小控键:可以拖动方形调整大小的句柄来调整元素的大小。 拖动时,手柄变成角度变角。
  • Android ConstraintLayout图文并茂详解(一)约束控键:单击约束句柄,在元素的每一侧显示为圆形,然后拖动到另一个约束句柄或父边界以创建约束。 约束由Z字形线表示。

点击视图以选择它。 然后单击并按住其中一个约束控键并将该行拖动到可用的锚点(另一个视图的边缘,父布局的边缘或GuideLine)。当释放时,将添加约束,默认边距分隔两个视图。这里,我们将一个Button的左侧面约束到父容器的的左侧:

Android ConstraintLayout图文并茂详解(一)

这样,我们就为Button创建了一个约束。

Android ConstraintLayout图文并茂详解(一)

可是,如上图,仔细看Layout Editor,有个标志Android ConstraintLayout图文并茂详解(一),点开后提示:大概意思是,Button缺少垂直约束,在运行后,其将在布局的左边。我们来看看约束的规则:

  • 每个视图必须至少有两个约束:一个水平和一个垂直。
  • 只能在约束控键和共享相同平面的锚点之间创建约束。因此,视图的垂直平面(左侧和右侧)可以仅限于另一个垂直平面; 基线只能限制在其他基线上
  • 每个约束控键只能用于一个约束,但可以创建多个约束(从不同的视图)到相同的锚点’

这也就是说,对于Button的约束而言,因为缺少了垂直约束,Layout Editor则会给出错误提示Android ConstraintLayout图文并茂详解(一)。尽管缺少的约束不会导致编译错误,但是会导致界面不能按照我们预想的显示。以后,我们在为视图添加约束时,尤其要注意Layout Editor的提示Android ConstraintLayout图文并茂详解(一),查看是否是否有缺少约束。为了避免缺少约束,Layout Editor可以使用自动连接(Autoconnect)和infer约束功能以便自动添加约束,至于这两种添加约束的方式,是否可行,后续再说。

约束到父容器

将视图的一边约束到布局的相应边缘。

在下图中,将视图的左侧连接到父容器的左边缘。 可以定义边缘与边距的距离。

Android ConstraintLayout图文并茂详解(一)

相对位置

在前面,我们已经知道如何给视图添加约束。现在,我们将通过约束来指定视图的位置。在ConstraintLayout中,Relative positioning,即相对位置是创建布局的基本构建模块之一。它类似RelativeLayout的layout_toLeftOf、alignParentLeft等这些属性。这些约束用来指定给定的控件相对于另一个控件的位置,可以在水平和竖直方向约束控件。

  • 水平方向: Left, Right, Start 和 End sides
  • 垂直方向: top, bottom sides 和 text baseline

Android ConstraintLayout图文并茂详解(一)

通常,将一个控件的约束边位于任何其他控件的另一侧。

例如:将按钮B放在按钮A的右边:

Android ConstraintLayout图文并茂详解(一)

如果

我么可以这么做:

<android.support.constraint.ConstraintLayout 
    ...>

    <Button
        android:id="@+id/btnRealA"
        .../>

    <Button
        android:id="@+id/btnRealB"
        ...
        app:layout_constraintStart_toEndOf="@+id/btnRealA" />
</android.support.constraint.ConstraintLayout>

上述代码,告诉我们,按钮B的左边被约束到按钮A的右侧,表示按钮B与按钮的A的右侧对齐。

Android ConstraintLayout图文并茂详解(一)

在ConstraintLayout中,定义了一系列的相对位置的约束属性,它们都将引用一个控件id,可以是任何其他视图,也可以是父容器(即引用父容器,即ConstraintLayout),表示视图的某侧被约束到指定视图/父容器的某侧。约束属性列表如下

  • 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_constraintBaseline_toBaselineOf
  • layout_constraintStart_toEndOf
  • layout_constraintStart_toStartOf
  • layout_constraintEnd_toStartOf
  • layout_constraintEnd_toEndOf

Android ConstraintLayout图文并茂详解(一)

刚才在设置按钮的B的约束是在xml里面设置的,前面已经提到了可以在Layout Editor里面通过拖动设置约束,我们可以这么做:

  1. 将两个Button拖到ConstraintLayout中
  2. 将约束从第二个Button的左侧拖到第一个右侧侧,如下图所示。 此约束将第二个Button水平放置第一个按钮,默认边距为8dp:

Android ConstraintLayout图文并茂详解(一)

这样,就不用再xml一行行的码代码了,只要拖动就好了,爽的要不得。。。

自动添加约束

在ToolBar中,曾提到一个工具 AutoconnectAndroid ConstraintLayout图文并茂详解(一),它是用来设置是否自动设置约束。如果将自动设置约束打卡,自动连接可以为父容器的视图元素创建两个或多个约束(因为一个视图最少有一个横向和一个竖向约束)。 将视图拖动到布局之后,它将基于元素的位置创建约束。

  • Android ConstraintLayout图文并茂详解(一):打开自动连接
  • Android ConstraintLayout图文并茂详解(一):关闭自动连接

    1. 打开layout_autoconnect.xml并切换到 Desgin选项卡
    2. Autoconnect工具位于工具栏中。默认情况下启用。
    3. 在blueprint或UI视图中,单击,然后将ImageView拖动到布局的中心,直到出现点阵指示。
    4. 当看到从上到下以及从左到右的GuidLine时,释放鼠标按钮。 将看到,表示约束的蓝色曲折线将视图的顶部,左侧,底部和右侧边缘连接到父视图的边缘,将ImageView放置在布局中

Android ConstraintLayout图文并茂详解(一)

约束被自动添加到视图的所有四面,我们可以看到ImageView位于Layout的中心,这是为何?让我们来看xml是如何定义的:

<ImageView
    android:id="@+id/imageView5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:srcCompat="@mipmap/ic_snow" />

从xml中可以看出,layout_constraintLeft_toLeftOf和layout_constraintRight_toRightOf是两个完全相反的约束。在ConstraintLayout中,如果在视图中添加两个相反的约束,则像弹簧一样,约束变得像一个弹簧一样表示相反的力。当视图大小设置为“fixed”或“wrap_content”时,效果最为明显.在这种情况下,视图以约束为中心。同样的,layout_constraintBottom_toBottomOf和layout_constraintTop_toTopOf也是两个完全相反的约束。这也不难解释为什么ImageView位于Layout的中心了。

删除约束

当ConstraintLayout里面的视图过多时,总避免不了一时手抖,或者其他原因,导致约束链接错误。我们该如何删除错误的约束呢?

  1. 选择该视图,然后单击预删除的约束控键。此时,只删除当前视图指定的约束。

    Android ConstraintLayout图文并茂详解(一)

  2. 通过选择视图,然后单击清除约束Android ConstraintLayout图文并茂详解(一),来删除该视图的所有约束

    Android ConstraintLayout图文并茂详解(一)

  3. 点击工具栏的Android ConstraintLayout图文并茂详解(一),删除所有视图的约束

    Android ConstraintLayout图文并茂详解(一)

对齐视图

Android ConstraintLayout图文并茂详解(一)

让我们来看上面的界面,其中一个明显的特点就是不同视图之间的对齐。UI在设计界面时,为了让界面更简洁,视图的对齐,肯定是一个优雅的处理方式之一。那么问题就来了,在ConstraintLayout该如何对齐呢?我们先了解对齐的概念,对齐就是将视图的边缘对齐另一个视图的相同边缘,或者是视图的中心对齐另一个视图的中心。

Android ConstraintLayout图文并茂详解(一)

在上图图中,B的左侧与A的左侧对齐,我们只需要将B左侧约束到A的左侧即可:

Android ConstraintLayout图文并茂详解(一)

刚才,只是将两个视图的一侧对齐了,如果想两个视图的中心对齐,应该怎么做呢?前面,我们提到过两个相反约束的作用,这里可以试一下,在两个视图的两边都创建约束:

Android ConstraintLayout图文并茂详解(一)
对于,在视图两边创建约束,视图对齐中心的原因这里不多描述,不了解可以看下前面对于两个相反约束的作用解释。

刚才只是,做了两个视图的对齐,如果是多个视图对齐,是不是就需要两两作对分别做约束呢,不用说也是特别的繁琐,必然不合理。既然不合理,那不用说也有工具了。在工具栏 7的作用是设置对齐方式。那么我们可以这么做

  1. 选择需要对齐的视图

    • 在Component Tree里手动选择
    • 在设计视图或者blueprint视图通过拖动的方式选择
  2. 通过工具栏选择对齐方式

    • 在Component Tree里右键点击被选择的视图,在Align或者Center中可以选择对齐方式

      Android ConstraintLayout图文并茂详解(一)

      Android ConstraintLayout图文并茂详解(一)

    • 在工具栏Android ConstraintLayout图文并茂详解(一)中选择对齐方式

      Android ConstraintLayout图文并茂详解(一)

下面,我们在在Component Tree中选择所需对齐的视图,然后在Component Tree里右键点击被选择的视图,在Align中选择视图中心对齐:

Android ConstraintLayout图文并茂详解(一)

基线约束

不管是英语还是其他语言(汉语除外),为了规范书写会设有四条线,从上至下第三条就是基线,以保证书写更整齐。如下所示:

Android ConstraintLayout图文并茂详解(一)

对于文本视图而言,例如TextView,EditText或Button,以使文本基线对齐,也为此设置了BaseLine相关属性,比如,RalativeLayout中的android:layout_alignBaseline属性用于设置当前组件与参照组件的基线对齐,或者是LinearLayout中的android:baselineAligned属性用于设置是否允许用户调整它内容的基线。关于传统布局的基线对齐,这里不多描述。我们还是关心ConstraintLayout中的文本视图的基线对齐。在ConstraintLayout中,使用基线约束来对齐使用不同文本大小的视图。即使视图中的文本元素大小不一,依然可以使用基线约束来对齐元素。这里我们来做个输入账号的界面:

  1. 将一个TextView从Palette拖到布局,其文本为”ID”,字体大小为18sp
  2. 将“Plain Tex”元素从“Palette”拖到布局(纯文本元素是EditText视图),其hint为”Please input the id”,字体大小为14sp
  3. 单击TextView“id”元素并将其指针悬停在其上。元素下方出现基线对齐的ab按钮,因为元素中包含文本:

    Android ConstraintLayout图文并茂详解(一)

  4. 单击ab按钮显示文本基线。然后从TextView“id”的基线(绿色闪烁)中单击并拖动到lain Tex的基线,如下图所示:

    Android ConstraintLayout图文并茂详解(一)

如果两个视图中的文本是多行,而且文本大小不一时,通过基线约束对齐,具体效果见下图:

Android ConstraintLayout图文并茂详解(一)

从上图中,我们可以清晰的看到:

  1. 如果作为基线的控件的内容为多行,则以第一行作为基线
  2. 基线对齐只是针对视图中的文本,而不是视图本身

约束到GuideLine

这里,先说说GuideLine是什么鬼。Guideline是ConstraintLayout的Guideline辅助对象的实用程序类,该辅助对象不会显示在设备上,它被默认是View.GONE,而且不可改。另外,Guideline是专门为ConstraintLayout创建的,也就是它仅也只能用于ConstraintLayou布局。

Guideline可以是水平或垂直的:

Android ConstraintLayout图文并茂详解(一)

  • 垂直Guideline的宽度为0,高度为ConstraintLayout的高度
  • 水平Guideline的宽度为ConstraintLayout的宽度,高度为0

GuideLine也可以认为是视图,其可以根据相对于布局边缘的dp或百分比,将GuideLine定位在布局中,位置确定有三种方式:

  • layout_constraintGuide_begin:指定与布局左侧或顶部的固定距离(dp)
  • layout_constraintGuide_end:指定与布局右侧或底部的固定距离(dp)
  • layout_constraintGuide_percent:指定与布局的宽度或高度的百分比

如果你想创建一个GuideLine,可以点击工具栏的Android ConstraintLayout图文并茂详解(一),然后在弹出框中选择水平的还是垂直的:

Android ConstraintLayout图文并茂详解(一)

在创建GuideLine以后,其默认的位置确认方式是layout_constraintGuide_begin,我们可以拖动虚线来重新指定它的位置。如果你想改变它的定位方式,单击GuideLine边缘的圆圈以切换测量模式。如下图所示。

Android ConstraintLayout图文并茂详解(一)

对于GuideLine的情况先说到这,接下来我们来了解Guideline有什么用?下面这个图,是登录界面一部分,可以清楚看出来,布局左右两边的pading是44dp。

Android ConstraintLayout图文并茂详解(一)

现在,我们创建一个GuideLine,其layout_constraintGuide_begin的值为44dp,然后把TextView(”账号”和密码)约束到GuideLine:

Android ConstraintLayout图文并茂详解(一)

到这里,我们知道GuideLine其实就是一种约束规则,供其他视图使用,以统一处理距离ConstraintLayout边缘的距离,而不用单独处理约束偏差。

对于GuideLine有个不解的地方,先看下面一段代码:

<android.support.constraint.ConstraintLayout 
    ....>

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        .../>

    <android.support.constraint.Guideline
        android:id="@+id/guideline2"
        .../>

    <Button
        android:id="@+id/button19"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="aaaaaaaaaaaaaaaaaaaaaaaaa"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"/>

</android.support.constraint.ConstraintLayout>

如上述代码所示,一个Button的左右两侧约束到两个垂直GuideLine,其width类型为wrap_content。如果Button中文本的长度超过两个GuideLine之间的距离时,Button本事会超过GuideLine的边界。如果将width类型为fixed,并指定其宽度大于两个GuideLine之间的距离时,依然如此。这样,必然会造成视图被覆盖的现象。

Android ConstraintLayout图文并茂详解(一)

如果将width类型修改为MATCH_CONSTRAINT,效果是这样的:

Android ConstraintLayout图文并茂详解(一)

造成这种问题的根本原因在于ConstraintLayout对于空间的计算方式。早在ConstraintLayout 1.0.2版本以前,有barriers用来协助约束,但是在1.0.2已经取消了这个辅助类。在这种情况下,是将width类型修设置为MATCH_CONSTRAINT还是限制文本显示的内容,这是我们值得考虑的问题。


本来打算一篇写完的,后来发现添加图片过多,导致篇幅很长,那就先说到这里,后续再写。到这里,本文主要介绍了Layout Editor的相关界面及在ConstraintLayoput中如何定位视图、对齐视图等。接下来,将了解如何修改视图的属性?如何处理带有链的线性视图组?

参考文档

  1. User ConstraintLayout to design your Android Views
  2. ConstraintLayout官方文档
  3. 使用 ConstraintLayout 构建自适应 UI
  4. 使用 Layout Editor 构建 UI