Android 减少布局层次—— ConstraintLayout 约束布局 的使用

一. 背景

当前手机APP项目中,有些界面比较复杂,导致布局层次很深,View的数量也相当多,对性能产生了一定影响;复杂的布局,同时也增大了代码维护的难度。

ConstraintLayout 正是为了解决这个问题,它支持以下几类强大的特性:
- 相对定位

  • Margins

  • 中心定位

  • 角度定位

  • Visibility behavior

  • 尺寸约束

  • 链(Chains)

  • Virtual Helpers objects

在组合使用这些特性以后,我们可以达到明显降低布局层次的目的。

二. 可行性

  1. ConstraintLayout 是以一个单独的support library 的形式提供的,他支持API 9以上的版本。
  2. Android Studio 2.2以上的版本
  3. 支持将旧的布局文件一键替换为ConstraintLayout,工作量较小(不支持将已有的多个层级的布局直接转换为同一层级);
    Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第1张图片

三. 引入步骤

在module的build.gradle中插入:

dependencies {
    ...
    //引入ConstraintLayout
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    ...
}

目前最新版本为1.1.0-beta3

四. 特性详解

1. 相对定位

相对定位是ConstrainLayout中最为经常使用的一项属性,它支持
水平方向:

  • left
app:layout_constraintLeft_toLeftOf
app:layout_constraintLeft_toRightOf
  • right
app:layout_constraintRight_toLeftOf
app:layout_constraintRight_toRightOf
  • start
app:layout_constraintStart_toEndOf
app:layout_constraintStart_toStartOf
  • end
app:layout_constraintEnd_toStartOf
app:layout_constraintEnd_toEndOf

竖直方向:

  • top
app:layout_constraintTop_toTopOf
app:layout_constraintTop_toBottomOf
  • bottom
app:layout_constraintBottom_toTopOf
app:layout_constraintBottom_toBottomOf
  • text baseline
app:layout_constraintBaseline_toBaselineOf

Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第2张图片

这些属性都需要引用到另一个控件,或者parent(指代他们的父容器,也就是ConstraintLayout)

2. Margins

支持设置Margin(仅支持0或正数):
Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第3张图片

跟其它布局所不同的是,ConstraintLayout还支持链接到Visibility为Gone时的Margin:

  • layout_goneMarginLeft

  • layout_goneMarginRight

  • layout_goneMarginStart

  • layout_goneMarginEnd

  • layout_goneMarginTop

  • layout_goneMarginBottom

五. 中心定位和偏移

1. 中心定位

我们看一下这种情况:

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

Button两端都被链接到了父容器的两端,如果
1. Button刚好和父容器相同宽度时,Button就相当于宽度设为了match_parent;

  1. Button小于父容器宽度时,约束就像两个相等的力,把Button往两边拉,这时,Button正好位于父容器水平方向的正中;

Button正好位于父容器水平方向的正中

2. 偏移(bias)

在中心定位时,我们可以对这两个约束力进行控制,使其偏向某一侧。例如,我们使控件偏向左侧:

<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/>
         

所产生的效果是:

正如你所见,这有点类似于百分比布局或LinearLayout的weight属性,这使得我们可以更好地适应不同的屏幕尺寸。

六. 角度定位(在支持库版本1.1中加入)

角度定位是ConstraintLayout所特有的一种布局方式,它可以约束一个控件的中心相对于另一个的角度和距离。你可以通过使用这些属性达到目的:

  • layout_constraintCircle: 角度定位相对的另一个控件的id

  • layout_constraintCircleRadius: 到相对控件中心的距离
    Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第4张图片

  • 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" />

七. Visibility behavior

如果控件与控件间存在约束关系,当其中的一个控件Visibility变为GONE时,ConstraintLayout仍然会保留这个约束关系,但这个View的Margin都会失效;这样可以确保不会影响到已有的布局。
Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第5张图片

八. 尺寸约束

1. 设置布局宽高

ConstraintLayout可以为布局设置宽高(android:layout_width 、android:layout_height),需要特殊注意的是,当设为0dp时,它的作用相当于MATCH_CONSTRAINT,而MATCH_PARENT在ConstraintLayout中是不被推荐使用的。

2. 设置布局最大最小尺寸

ConstraintLayout可以对布局的高度和宽度进行限制:
- android:minWidth:最小宽度

  • android:minHeight:最小高度

  • android:maxWidth:最大宽度

  • android:maxHeight:最大高度

注意:这些属性仅在宽高设为WRAP_CONTENT时有效!

3. WRAP_CONTENT

在ConstraintLayout中,仍然可以对WRAP_CONTENT的最大尺寸进行约束:
- app:layout_constrainedWidth=”true|false”

  • app:layout_constrainedHeight=”true|false”

当其中一个被设置为true时,控件的最大宽高任然可以被约束链约束,需要注意的是,这样做会使布局变慢一些。

4. MATCH_CONSTRAINT(在支持库版本1.1中加入)

当宽高被设为MATCH_CONSTRAINT,这个控件将尝试占据布局上所有可用的地方,但同时会被这些属性所限制:
- layout_constraintWidth_min/layout_constraintHeight_min:最小宽高

  • layout_constraintWidth_max/layout_constraintHeight_max:最大宽高

  • layout_constraintWidth_percent/layout_constraintHeight_percent:宽高相对于父容器的百分比。

注意
1. 这些属性同时可以设置为wrap;

  1. 当使用百分比尺寸的时候,应当设置宽高为MATCH_CONSTRAINT;

  2. 父容器需要设置app:layout_constraintWidth_default=”percent”或app:layout_constraintHeight_default=”percent”(在1.1-beta2以后不再必须设置)

5. 设置比例
constraintLayout支持子控件设置其宽高比,要使该特性生效至少需要将宽高中的一个设置为0dp(MATCH_CONSTRAINT)

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

app:layout_constraintDimensionRatio可以设置为两种格式:
1. 一个float类型的数值,代表宽与高之间的比例;

  1. 宽:高

注意:
当宽高均被设为0dp时,父容器将尝试在满足所有约束条件及比例的同时,占据最大的宽高;
如果只想对某个方向设置比例,则可以在属性前面加上W或H,与比例以,隔开:

<Button android:layout_width="0dp"
                   android:layout_height="0dp"
                   app:layout_constraintDimensionRatio="H,16:9"
                   app:layout_constraintBottom_toBottomOf="parent"
                   app:layout_constraintTop_toTopOf="parent"/>

九. 链(Chains)

1. 概念

链使我们能够对一组在水平或竖直方向互相关联的控件的属性进行统一管理。成为链的条件是:一组控件他们通过一个双向的约束关系链接起来。
Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第6张图片

注意:链的属性是由一条链的头结点控制的。而头结点的定义是一条链中位于最左端的控件。
链的头结点

2. 链的Margins

ConstraintLayout支持对链添加Margin,如果这条链的控件是分散分布的,将会从已分配给链的空间中减去设置的链边距。

3. 链的Style

链支持设置他们的Style,只需在头结点指定layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle。共支持五种类型:
- CHAIN_SPREAD(默认值):链中的元素将分散分布;

  • Weighted chain:在CHAIN_SPREAD模式中,如果某些组件被设置成MATCH_CONSTRAINT,他们将会占据所有空余空间并分散分布;

  • CHAIN_SPREAD_INSIDE:类似于CHAIN_SPREAD,但链的两端不会分散;

  • CHAIN_PACKED:链中的元素将会紧密相连在一起,偏移(bias)的设定将会影响他们在容器中所处的位置

  • Weighted chains:当链处在默认的模式(CHAIN_SPREAD)且其中一个或多个元素被设置为MATCH_CONSTRAINT时,他们将平均占据剩下的空余空间;如果其中的结点同时设置了
    layout_constraintHorizontal_weight或layout_constraintVertical_weight属性,那么他们将根据所设置的比重来分配剩下的空间。
    Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第7张图片

十. Virtual Helper objects

虚拟辅助类部件它们最终不会在界面上呈现出来,但可以帮助我们更好更精细地控制布局。目前。所支持的这类部件包括:

1. Guideline

Guideline可以放在竖直方向或水平方向,水平Guideline的高为0,宽度与父容器一致;竖直Guideline同理。
Guideline 具有三类特殊的属性:
- layout_constraintGuide_begin:设置Guideline 距离父容器起始位置的距离(left或top);

  • layout_constraintGuide_end:设置Guideline 距离父容器尾部的距离(right或bottom);

  • layout_constraintGuide_percent:设置Guideline 相对于父容器宽度/高度的百分比位置。

例如,设置一条竖直方向的Guideline:

<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:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5"/>

android.support.constraint.ConstraintLayout>

Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第8张图片

2. Barrier(在支持库版本1.1中加入)

Barrier 使用多个控件作为参考,在这些控件中,选取在特定方向最边缘的的控件创建一条Guideline。
constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。
例如,假设已有两个按钮:
Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第9张图片
Barrier 设置为:

<android.support.constraint.Barrier
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="bt_1,bt_2"/>

此时Guideline 的位置为:
Android 减少布局层次—— ConstraintLayout 约束布局 的使用_第10张图片

3. Group(在支持库版本1.1中加入)

Group 用于控制所引用的一组控件的可见性(Visibility),constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。

<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" />

注意:多个Group 部件可以引用相同的控件,这时Group 在xml中的定义顺序将决定这个控件最终的可见性。

你可能感兴趣的:(Android 减少布局层次—— ConstraintLayout 约束布局 的使用)