ConstraintLayout 介绍与实战

介绍

ConstraintLayout 在 2016 年 Google IO 中面世,它的出现是为了解决开发中过于复杂的页面层级嵌套过多的问题——层级过深会增长绘制界面须要的时间,影响用户体验。android

在使用过程当中,ConstraintLayout 能够看作是一个更强大的 RelativeLayout,它提供了更多的 API 来约束控件的相对关系,更容易知足复杂的页面布局。app

布局属性

约束布局拥有更强大的约束能力,其拥有的布局属性数量也很是多,笔者在这里进行分类讲解。ide

相对定位属性

相对定位是约束布局中建立布局的基本属性之一。这些属性和 RelativeLayout 布局属性是相似的,用来控制控件相对于另一个控件或者父容器的位置。布局

分别能够在水平轴和垂直轴上约束控件:动画

  • Horizontal: left, right, start, end
  • Vertical: top, bottom, text baseline

简单来讲就是将给定一侧须要约束的控件约束到另外一个控件的另外一侧。 举个例子,把按钮 B 放到按钮 A 的右边:ui

咱们能够这样写:spa

<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ... app:layout_constraintLeft_toRightOf="@+id/buttonA" />
复制代码

除了指定另一个控件 id 进行约束,咱们还能够与父布局进行约束:设计

<Button android:id="@+id/buttonB" ... app:layout_constraintLeft_toLeftOf="parent" />
复制代码

Margins

设置控件的间距属性与其余布局相同,但约束布局中对应间距值生效须要有对应的约束条件,好比须要给控件设置左间距,那该控件它的 constraint<Left/Start>_toXXXOf 必定须要,不然间距没法生效。3d

与其余控件不一样的是新增了一系列 goneMargin 属性,用来控制当约束目标可见性为 GONE 的时候,设置不一样的间距值。code

实践过程当中笔者可以想到的一个场景需求是:

在动画中,A 不可见的时候,须要保证 B 的布局位置不变,这个时候设置 goneMarginStart 的值为 A 的宽度加上 B 的 marginStart ,就能够知足该需求。

居中和 Bias

居中

跟其余布局同样,约束布局一样拥有子控件居中的能力,居中定位是以横向/竖向两端同时约束来定位布局位置。好比让 A 在父容器中左右居中:

<android.support.constraint.ConstraintLayout ...>
  <Button android:id="@+id/button" ... app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 复制代码

竖直居中同理。

Bias

上述布局约束会把控件居中对齐,使用 bias 能够进行偏移。

  • layout_constraintHorizontal_bias
  • layout_constraintVertical_bias

若是没有设置 bias 值,则左右两边取值各占有 50% 也就是居中的效果,若是把 bias 修改成 0.3 (30%),则左边空白的边距会减小,右边会相应增多。

给上述代码增长一行 app:layout_constraintHorizontal_bias="0.3" ,就能够获得图片的效果。

<android.support.constraint.ConstraintLayout ...>
  <Button android:id="@+id/button" ... app:layout_constraintHorizontal_bias="0.3" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 复制代码

相对圆周定位 (ver 1.1)

constraintCircle 属性在 1.1 版本中添加,提供开发者相对控件的中心一个角度和距离上约束另一个控件的能力。

  • layout_constraintCircle
  • layout_constraintCircleRadius
  • layout_constraintCircleAngle

<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ... app:layout_constraintCircle="@+id/buttonA" app:layout_constraintCircleRadius="100dp" app:layout_constraintCircleAngle="45" />
复制代码

控件的尺寸约束

ConstraintLayout 中设置控件的高度和宽度是经过 android:layout_widthandroid:layout_height 来指定,但有三种不一样类型:

  1. 使用肯定的尺寸,给定数值,好比 36dp
  2. 使用 WRAP_CONTENT 该效果与其余控件相同
  3. 使用 0dp 来表示 MATCH_CONSTRAINT, 意思是根据约束规则指定高宽

(a) 设置为 WRAP_CONTENT;(b) 设置为 0dp;(c) 是设置了 margin 状况下的 (b)

WRAP_CONTENT 下的强制约束 (ver 1.1)

在 1.1 版本以前,约束布局对于控件的 WRAP_CONTENT 是不会限制它的结果大小。因此这在你但愿使用 WRAP_CONTENT 但仍然须要强制约束条件来限制它的结果,就可能须要添加如下属性:

  • app:layout_constrainedWidth="true|false"
  • app:layout_constrainedHeight="true|false"

在最后业务实战的第一个例子中会具体说明该属性的使用场景

宽高比例

layout_constraintDimensionRatio 限制控件的宽高比,若是要使用宽高比来约束尺寸,则至少要设置宽高其中一个尺寸为0dp,而后再设置上 layout_constraintDimentionRatio 属性。

<Button android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" />
复制代码

上述代码会获得一个高度跟宽度相同的 Button。

关于比例的取值有两种方式:

  • float 值,表明宽度/高度的比率
  • 宽度:高度这种比率值,好比 9:16

若是宽高都是 MATCH_CONSTRAINT (0dp) 也能够是用宽高比,这种状况系统会使用知足全部约束条件和宽高比率的最大尺寸。若是要根据其中一个尺寸来约束另一个尺寸,能够在比率数值前添加 "W/H" 来分别约束宽度或者高度。 举例:app:layout_constraintDimensionRatio="H,16:9"

这行代码表示约束该 View 的高度,其数值须要符合 16:9 的比率。

链条

Chains 为同一个方向(水平或者垂直)上的多个控件提供一个相似群组的概念。其余的方向则能够单独控制。

建立链条

多个控件相互在同一个方向上双向引用就能够建立一个 Chain.

Chain Style

如下属性是用来控制 Chain Style 的:

– layout_constraintHorizontal_chainStyle – layout_constraintHorizontal_weight – layout_constraintVertical_chainStyle – layout_constraintVertical_weight

其中 Style 有 4 种:

  1. CHAIN_SPREAD 这个是默认的 Style, 里面的全部控件会分散开布局
  2. Weighted chain,在 CHAIN_SPREAD 模式下,若是有些控件的尺寸设置为 MATCH_CONSTRAINT(0dp),则这些控件尺寸会占据全部剩余可用的空间,和 LinearLayout weight 相似。
  3. CHAIN_SPREAD_INSIDECHAIN_SPREAD 相似,只不过两端的两个控件和父容器直接不占用多余空间,多余空间在控件之间分散
  4. CHAIN_PACKED 这种模式下,全部的控件都居中汇集在一块儿,可是能够设置 bias 属性来控制汇集的位置。

辅助布局

Guideline

Guideline 是约束布局中一个特殊的辅助布局类,能够建立水平或者垂直的参考线,其余的控件能够根据这个参考线来进行布局,它本质是不可见的控件。

参考线的位置属性:

  • orientation:vertical/horizontal
  • layout_constraintGuide_begin 指定距离左/上边开始的固定位置
  • layout_constraintGuide_end 指定距离右/下边开始的固定位置
  • layout_constraintGuide_percent 指定位于布局中所在的百分比

Barrier

Barrier 在约束布局中经过 constraint_referenced_ids 引用多个控件,看做一个总体来添加一个与另一个控件限制最大宽/高的约束。

经过 app:barrierDirection 属性来决定 Barrier 的方向。

<android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="start" app:constraint_referenced_ids="button1,button2" />
复制代码

Group

Group 是约束布局用来控制一组控件的可见性。

<android.support.constraint.Group android:id="@+id/group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="visible" app:constraint_referenced_ids="button4,button9" />
复制代码

被引用 id 的控件的可见性(visibility)和深度(elevation)属性与 Group 相同。

换句话说:被 Group 引用的控件会致使它们的自身的可见性和深度失效。

业务经典场景

1. 固定一边,中间宽度可变,另外一边跟随中间尾部

设计需求:头像位置固定,中间文字长度可变,最右侧按钮跟在文字右侧,但不能超出屏幕。

<androidx.constraintlayout.widget.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:layout_width="match_parent" android:layout_height="60dp" tools:background="@color/background_gray">

      <ImageView android:id="@+id/iv_avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginStart="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars[2]" />

      <TextView android:id="@+id/tv_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" android:singleLine="true" app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="@+id/iv_avatar" app:layout_constraintEnd_toStartOf="@id/tv_action" app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toEndOf="@id/iv_avatar" app:layout_constraintTop_toTopOf="@+id/iv_avatar" tools:text="ConstraintLayout is available as a support library" />

      <TextView android:id="@+id/tv_action" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="15dp" app:layout_constraintBottom_toBottomOf="@+id/iv_avatar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/tv_text" app:layout_constraintTop_toTopOf="@+id/iv_avatar" tools:text="查看" />


</androidx.constraintlayout.widget.ConstraintLayout>

复制代码

该场景重点须要熟悉属性:layout_constrainedWidth/Height 应用。

2. 根据某个 View 的高度/宽度,来居中一组 View

设计需求:右侧图片和文字,须要总体跟左边头像居中。

<androidx.constraintlayout.widget.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:layout_width="match_parent" android:layout_height="300dp" tools:background="@color/background_gray">

    <ImageView android:id="@+id/iv_avatar" android:layout_width="150dp" android:layout_height="150dp" android:layout_marginStart="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" tools:srcCompat="@tools:sample/avatars[2]" />

    <ImageView android:id="@+id/iv_pic" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginStart="50dp" android:scaleType="centerCrop" app:layout_constraintBottom_toTopOf="@+id/tv_content" app:layout_constraintStart_toEndOf="@id/iv_avatar" app:layout_constraintTop_toTopOf="@id/iv_avatar" app:layout_constraintVertical_chainStyle="packed" tools:srcCompat="@tools:sample/backgrounds/scenic[6]" />

    <TextView android:id="@+id/tv_content" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="5dp" app:layout_constraintBottom_toBottomOf="@id/iv_avatar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/iv_pic" app:layout_constraintTop_toBottomOf="@+id/iv_pic" tools:text="Chains provide group-like behavior in a single axis (horizontally or vertically). " />
</androidx.constraintlayout.widget.ConstraintLayout>

复制代码

该场景重点须要熟悉约束布局:Chain 的应用。 iv_pictv_content 双向依赖,使用 packed Style 让它们紧靠一块儿,同时,iv_pic 头部与 iv_avatar 的头部对齐, tv_content 的底部与 iv_avatar 的底部对齐,达到它们居中显示的效果。

相关文章
相关标签/搜索