ConstraintLayout
在 2016 年 Google IO 中面世,它的出现是为了解决开发中过于复杂的页面层级嵌套过多的问题——层级过深会增长绘制界面须要的时间,影响用户体验。android
在使用过程当中,ConstraintLayout
能够看作是一个更强大的 RelativeLayout
,它提供了更多的 API 来约束控件的相对关系,更容易知足复杂的页面布局。app
约束布局拥有更强大的约束能力,其拥有的布局属性数量也很是多,笔者在这里进行分类讲解。ide
相对定位是约束布局中建立布局的基本属性之一。这些属性和 RelativeLayout
布局属性是相似的,用来控制控件相对于另一个控件或者父容器的位置。布局
分别能够在水平轴和垂直轴上约束控件:动画
简单来讲就是将给定一侧须要约束的控件约束到另外一个控件的另外一侧。 举个例子,把按钮 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" />
复制代码
设置控件的间距属性与其余布局相同,但约束布局中对应间距值生效须要有对应的约束条件,好比须要给控件设置左间距,那该控件它的 constraint<Left/Start>_toXXXOf
必定须要,不然间距没法生效。3d
与其余控件不一样的是新增了一系列 goneMargin
属性,用来控制当约束目标可见性为 GONE
的时候,设置不一样的间距值。code
实践过程当中笔者可以想到的一个场景需求是:
在动画中,A 不可见的时候,须要保证 B 的布局位置不变,这个时候设置 goneMarginStart
的值为 A 的宽度加上 B 的 marginStart
,就能够知足该需求。
跟其余布局同样,约束布局一样拥有子控件居中的能力,居中定位是以横向/竖向两端同时约束来定位布局位置。好比让 A 在父容器中左右居中:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ... app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 复制代码
竖直居中同理。
上述布局约束会把控件居中对齐,使用 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/> </> 复制代码
constraintCircle
属性在 1.1 版本中添加,提供开发者相对控件的中心一个角度和距离上约束另一个控件的能力。
<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_width
和 android:layout_height
来指定,但有三种不一样类型:
36dp
WRAP_CONTENT
该效果与其余控件相同0dp
来表示 MATCH_CONSTRAINT
, 意思是根据约束规则指定高宽(a) 设置为 WRAP_CONTENT
;(b) 设置为 0dp;(c) 是设置了 margin
状况下的 (b)
WRAP_CONTENT
下的强制约束 (ver 1.1)在 1.1 版本以前,约束布局对于控件的 WRAP_CONTENT
是不会限制它的结果大小。因此这在你但愿使用 WRAP_CONTENT
但仍然须要强制约束条件来限制它的结果,就可能须要添加如下属性:
在最后业务实战的第一个例子中会具体说明该属性的使用场景
layout_constraintDimensionRatio
限制控件的宽高比,若是要使用宽高比来约束尺寸,则至少要设置宽高其中一个尺寸为0dp
,而后再设置上 layout_constraintDimentionRatio
属性。
<Button android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" />
复制代码
上述代码会获得一个高度跟宽度相同的 Button。
关于比例的取值有两种方式:
若是宽高都是 MATCH_CONSTRAINT (0dp)
也能够是用宽高比,这种状况系统会使用知足全部约束条件和宽高比率的最大尺寸。若是要根据其中一个尺寸来约束另一个尺寸,能够在比率数值前添加 "W/H" 来分别约束宽度或者高度。 举例:app:layout_constraintDimensionRatio="H,16:9"
这行代码表示约束该 View 的高度,其数值须要符合 16:9 的比率。
Chains 为同一个方向(水平或者垂直)上的多个控件提供一个相似群组的概念。其余的方向则能够单独控制。
多个控件相互在同一个方向上双向引用就能够建立一个 Chain.
如下属性是用来控制 Chain Style 的:
– layout_constraintHorizontal_chainStyle – layout_constraintHorizontal_weight – layout_constraintVertical_chainStyle – layout_constraintVertical_weight
其中 Style 有 4 种:
CHAIN_SPREAD
这个是默认的 Style, 里面的全部控件会分散开布局CHAIN_SPREAD
模式下,若是有些控件的尺寸设置为 MATCH_CONSTRAINT(0dp)
,则这些控件尺寸会占据全部剩余可用的空间,和 LinearLayout weight 相似。CHAIN_SPREAD_INSIDE
和 CHAIN_SPREAD
相似,只不过两端的两个控件和父容器直接不占用多余空间,多余空间在控件之间分散CHAIN_PACKED
这种模式下,全部的控件都居中汇集在一块儿,可是能够设置 bias 属性来控制汇集的位置。Guideline 是约束布局中一个特殊的辅助布局类,能够建立水平或者垂直的参考线,其余的控件能够根据这个参考线来进行布局,它本质是不可见的控件。
参考线的位置属性:
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 是约束布局用来控制一组控件的可见性。
<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 引用的控件会致使它们的自身的可见性和深度失效。
设计需求:头像位置固定,中间文字长度可变,最右侧按钮跟在文字右侧,但不能超出屏幕。
<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
应用。
设计需求:右侧图片和文字,须要总体跟左边头像居中。
<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_pic
与 tv_content
双向依赖,使用 packed
Style 让它们紧靠一块儿,同时,iv_pic
头部与 iv_avatar
的头部对齐, tv_content
的底部与 iv_avatar
的底部对齐,达到它们居中显示的效果。