Android 干货精粹

[原]手把手教你ConstraintLayout

2019-10-04  本文已影响0人  FredWhite

开篇

这是我写的第一篇技术博客。其实有点不知道从何说起,所以索性就从Android布局中的 ConstraintLayout(约束布局) 说起吧。

ConstraintLayout 从一出生就吸引万千目光。在2016年Google I/O大会上,它被隆重的介绍出来。它的问世完美解决了困扰开发者多年的 RelativeLayoutLinearLayout 布局嵌套过多的问题。

ConstraintLayout 从Android Api 9 以上就可以使用啦!从 Android Studio 2.3 起,官方的默认布局模板就使用的是 ConstraintLayout。

尽管目前网上有很多详细介绍ConstraintLayout的优秀文章,我还是决定写一篇关于ConstraintLayout的文章,目的是删繁就简。不会过多的去延伸和拓展相关知识,只为可以让开发者通过本篇对ConstraintLayout的介绍,快速掌握和使用ConstraintLayout。那么本篇的目的就达到啦!

我为什么需要它?

两句话解释。

第一句:ConstraintLayout 使用约束的方式指定各个控件的位置和关系。
(何谓约束的方式?参见下面章节详细解释)

第二句:当项目中遇到复杂布局时,会通过RelativeLayout 与 LinearLayout 互相多层嵌套实现(严重影响性能),而ConstraintLayout则一个就搞定!
(为何一个就搞定?参见第一句解释)

我什么时候使用它?

一句话建议。

当布局嵌套超过3层 (>=3) 的时候,就可以考虑直接上 ConstraintLayout 啦!

我怎么使用它?

第一步:引用

由于 ConstraintLayout 并不是Android SDK集成的,而是作为非绑定( Unbundled ) 的支持库去引用 ,所以,我们首先需要在 app 的 build.gradle 里引用它。

dependencies {
    compile 'com.android.support.constraint:constraint-layout:1.1.3'
}

(请确保你的Android Studio版本在 2.2 以上)

第二步:新建布局xml

在工程的 res → layout 下面新建 layout_constraint.xml 文件(名字可自定),初始化布局如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.constraint.ConstraintLayout>

第三步:可视化拖拽控件至ConstraintLayout窗体中

从事Android开发的同学应该都知道,尽管IDE为我们提供了可视化的布局界面,但一般我们进行布局的时候,都不会使用它,因为操作起来非常不方便,很难快速实现我们想要的布局效果。所以我们会直接通过代码进行布局。

But 对于 ConstraintLayout 而言,可视化布局恰恰成为了一大利器。因为 ConstraintLayout 非常适合利用可视化布局界面进行布局,操作简便,且能快速实现所需效果。

如下图所示,在 ConstraintLayout 中可视化布局一个 Button ,呈居中效果。

可视化布局.gif
布局完成后,Android Studio 会自动生成相关代码。如上图,布局完成后的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

看到这段代码后,我想大家应该都注意到了 Button 中末尾4行的属性,也就是

app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

这4个属性是 ConstraintLayout 所独有的。命名空间是“app:”,即来源于本地包的命名空间。我们后面会详细讲解这些属性。如果有些同学习惯用代码进行布局的话,就需要更加熟练掌握这些属性的含义和用法哦!

第四步:ConstraintLayout布局属性解析

先来给大家上幅图,关于相对位置约束的。

相对位置约束.png
接下来我们再来说说一直都在说的 ConstraintLayout约束布局 到底是个什么东西?

ConstraintLayout约束布局:其实就是根据布局中的其他元素或视图控件,确定当前视图控件在屏幕中的位置。其中视图控件受到三类约束,即其他视图控件 、 父容器( parent )、基准线 ( Guideline )。

4.1 标准属性

它的标准属性模板如下:

app:layout_constraint [本源位置]_[目标位置]="[目标 ID]"

例如:

app:layout_constraintTop_toTopOf="@+id/constraintLayout"

即在约束布局 ConstraintLayout 中,视图控件的约束是:将“当前视图 的顶部”约束至“目标视图的顶部”,目标视图的名称 ID 是 constraintLayout。 也就是说,把当前视图的顶部对齐到 constraintLayout 布局的顶部。这是约束布局的表述方式,在约束布局中,所有复杂的排列都是通过类似的形式组合在一起的。具体的有如下一些属性:

以上属性根据上面提供的 相对位置约束图 ,相信大家可以很好的理解属性的含义及用法。那么问题来了,图上面 leftstart,以及 rightend 都位于同一个地方,那么是否也就是说如下两个属性含义相同?

app:layout_constraintLeft_toLeftOf
app:layout_constraintStart_toStartOf

答案是 不同。再准确点来说,视两种情况而定。

  1. 布局方向是 LTR(left-to-right),那么 start == left,end == right;(默认)
  2. 布局方向是 RTL(right-to-left),那么 start == right,end == left。

Android默认的布局方向是 LTR,也就是说,一般情况下,都是第一种情况。如果想要设置成 RTL,则需要在 Manifest文件 中的 <application> 节点中添加属性 android:supportsRtl=true。此时,便成了第二种情况。(需要Android API >= 17)

4.2 Bais属性

由第三步可知,通过下面4个属性,可以让Button呈现 居中 效果。但如果项目的布局要求该Button偏向其中一侧布局,应该怎样做呢?

app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

此时就需要用到 Bais 属性了。主要分为两种:

例如,我们设置水平偏差为0.3,也就是30%,则会呈现下图所示效果。

layout_constraintHorizontal_bias=0.3.png
同样适用于垂直偏差。回到我们的布局文件 layout_constraint.xml 上来,如果我们设置水平偏差=0.3,垂直偏差=0.6。则效果如下: Bais属性设置.png

上述效果对应的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.6" />
</android.support.constraint.ConstraintLayout>

好啦!关于Bais属性的就介绍到这里啦!接下来,我们会介绍其他好玩儿的属性

4.3 角度约束

角度约束,顾名思义,就是通过 角度(angle)距离(radius) 来约束两个控件的中心位置。老规矩,先来张图。

角度约束.png
角度约束主要涉及到以下三个属性:

两个控件中心位置之间的关系如下图所示:


空间中心位置关系.png

回到我们的布局文件 layout_constraint.xml 上来,新增一个 Button2 ,通过设置角度定位属性(角度45°,距离200dp)实现如下效果。

角度定位示例.png
以上效果的代码段如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.6" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintCircle="@id/button1"
        app:layout_constraintCircleAngle="45"
        app:layout_constraintCircleRadius="200dp" />

</android.support.constraint.ConstraintLayout>

需要注意的是,角度定位属性是在 ConstraintLayout API 1.1 以 才出现的新增属性。所以如果你想要使用该属性,需要确保你引用的ConstraintLayout 的 版本号 >=1.1。目前最新的版本是 1.1.3。

4.4 尺寸约束

在Android布局文件中,对于尺寸的设置必不可少,然而对于Layout的尺寸约束,在以前经常让我们头痛,比如,对于LinearLayout的尺寸约束,如果想要限制它的最大宽,我们一般会考虑设置

android:maxWidth=100dp

然后,就没有然后了 接着,我们尝试用

android:layout_maxWidth=100dp

然后,可爱的红色感叹号就跳出来了
现在,ConstraintLayout的横空出世,终于,让这个问题不再是问题!

4.4.1 最大最小尺寸约束

可以通过如下四个属性对 ConstraintLayout 自身 进行最大最小宽高约束。

由于这几个属性的含义和使用场景大家已经烂熟于心了,我这里就不一一演示了

4.4.2 内部控件尺寸约束

ConstraintLayout 内部控件的尺寸设置可以通过如下三种方式进行:

前两种尺寸设置无需赘言。重点是第三种约束设置。如果设置了0dp,那么则可以根据需要进行如下三种关联设置:

老规矩,先上效果图如下。


尺寸约束.png

以上效果的代码段如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.7"
        app:layout_constraintHeight_percent="0.2"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button1" />

    <Button
        android:id="@+id/button3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="200dp"/>

</android.support.constraint.ConstraintLayout>

由代码可以清晰知道,

- Ratio 属性(宽高比 width:height)

layout_width 或者 layout_height 设置为 一个 0dp,另一个为固定值 后,可以进行宽高比属性(ratio)设置。一般常用于设置 ImageView 等控件上。
所涉及到的属性如下:

照例先上效果图。


Ratio 属性示例.png

以上效果的代码段如下:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:background="@color/colorAccent"
        android:src="@drawable/naruto"
        app:layout_constraintDimensionRatio="16:9"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:background="@color/colorAccent"
        android:src="@drawable/naruto"
        app:layout_constraintDimensionRatio="H,16:9"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

由以上代码及示例图可以清晰知道,ratio默认设置比为 W:H 即 width:height,即以下两句代码等价:

app:layout_constraintDimensionRatio="16:9"
app:layout_constraintDimensionRatio="W,16:9"

而如果设置为 “H,16:9” 则表示该比值为 H:W 即 height:width,如图中 第二个 ImageView 控件 所示。

4.5 链式约束

链式约束就比较有意思了,也非常实用,关键理解很简单。先上一张图看了再说!

链式约束类型.png
由上图可以得出,链式约束总共有 5种类型,具体含义如下:

链式约束涉及到的属性值有2个,分别是 水平链式约束垂直链式约束

我们以 Spread Chain 为例来说明链式约束的使用。上图。

Spread Chain.png
以上效果的代码段如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Center1111"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="@+id/constraintLayout"
        app:layout_constraintRight_toLeftOf="@+id/btn2"
        app:layout_constraintTop_toTopOf="@+id/constraintLayout" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Center2"
        app:layout_constraintLeft_toRightOf="@+id/btn1"
        app:layout_constraintRight_toLeftOf="@+id/btn3"
        app:layout_constraintTop_toTopOf="@+id/constraintLayout" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:text="Center3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn2"
        app:layout_constraintTop_toTopOf="@+id/constraintLayout" />

</android.support.constraint.ConstraintLayout>

除了上面所说的两种链式约束外,还有一种 比重链式约束(weight chains)。所涉及到的属性如下(同样分为 水平垂直 两种):

该属性的含义、使用以及效果,同 LinearLayout 下的 weight 属性相似,故在此不再过多介绍。感兴趣的童鞋可以自己去试试

第五步:Guideline介绍

Guildline像辅助线一样,在预览的时候帮助你完成布局(不会显示在界面上)。关于Guideline的作用及使用场景留给童鞋们自己去探索

除了你所介绍的,我还可以从哪儿获取关于ConstraintLayout最新的信息?

一句话总结。
关于ConstraintLayout最权威的信息当然是直接去官方文档查看啦!

好啦!至此我们的第一篇《手把手教你掌握ConstraintLayout》就到此结束啦!希望可以给各位童鞋带起来一点点的帮助,那么本篇的目的就达到啦!

第一次写技术博客,难免有错误疏漏之处,欢迎各位童鞋批评指正!
我是 FredWhite,你们的好盆友,我在这儿等着你!

上一篇 下一篇

猜你喜欢

热点阅读