天天看点

ConstraintLayout详解

1.介绍

约束布局

ConstraintLayout

本身就是一个ViewGroup,它用来解决布局嵌套过多的问题(嵌套越多,绘制消耗的时间越长),以灵活的方式定位/调整小部件(API 9以上均可使用),相比RelativeLayout更灵活,性能更加的出色,更好的适配屏幕大小不同的机型。Android Studio 2.3开始默认创建Activity是都是使用它。

2.使用

使用它也非常的简单,高版本的AS通常都会自动的添加它的依赖,如果未添加依赖在app/build.gradle中添加相应的依赖即可。

implementation 'com.android.support.constraint:constraint-layout:1.1.3'
           

2.1 相对定位

即一个组件相对于另一个组件的约束,非常的好理解(与RelativeLayout非常的类似)。

例:要实现B在A的右侧:

ConstraintLayout详解

按钮A在按钮B的右侧,也可以理解为按钮B的左侧位于按钮A的右侧;其他的方位都一样。我们在代码中的表示如下:

<Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintLeft_toRightOf="@id/btn1" />
           

其中最关键的属性为

app:layout_constraintLeft_toRightOf="@id/btn1"

,代表按钮B的左侧位于按钮A的右侧

其中常用的属性还有:

// 值可以为parent,意思就是A的左侧位于父布局的左侧(top_top|bottom_bottom等一样)
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
           

引用官方的一张图来说明这些属性:

ConstraintLayout详解

比较特殊的有

layout_constraintBaseline_toBaselineOf

,如图所示,两个Button的高度不一致,但是又希望他们文本对齐,这个时候就可以使用

layout_constraintBaseline_toBaselineOf

保证文字相对齐:

ConstraintLayout详解
<Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:text="Button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:text="Button4"
        app:layout_constraintBaseline_toBaselineOf="@id/btn3"
        app:layout_constraintLeft_toRightOf="@id/btn3" />
           

2.2 角度定位

角度定位指的是利用角度以及距离决定某些控件中心点的坐标。

三个属性为:

  1. app:layout_constraintCircle="@id/btn3"

    指定相对于哪个控件
  2. app:layout_constraintCircleAngle="160"

    角度
  3. app:layout_constraintCircleRadius="150dp"

    中心点的距离

其中的关系如下图所示:

ConstraintLayout详解

例子:按钮5在按钮3的160度方向距离为150dp

<Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:text="Button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 <Button
        android:id="@+id/btn5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button5"
        app:layout_constraintCircle="@id/btn3"
        app:layout_constraintCircleAngle="160"
        app:layout_constraintCircleRadius="150dp" />
           

效果图:

ConstraintLayout详解

2.3 Margin

使用Margin时,用法与其他布局的一致,前提条件是:必须指定了相对应的约束,Margin值只能大于等于0。

唯一特殊的地方:在对应约束的控件隐藏时,相当于一个点,可使用如下Margin来设置隐藏后的Margin值

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
           

2.4 居中偏移

如何实现居中:即利用相对定位中的4个属性即可

app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintLeft_toLeftOf="parent"
 app:layout_constraintRight_toRightOf="parent"
 app:layout_constraintTop_toTopOf="parent"
           

偏移(Bias): 使用

app:layout_constraintHorizontal_bias="0.3"

属性即可(值在0-1之间)

1.

layout_constraintHorizontal_bias 水平偏移

2.

layout_constraintVertical_bias 垂直偏移

上下居中,水平偏移为0.3

ConstraintLayout详解

2.5 尺寸约束

提供了一下四种方式:

  1. 固定值
  2. wrap_content,自己进行计算

    当控件的高度或宽度为wrap_content时,可以使用下列属性来控制最大、最小的高度或宽度:

    android:minWidth 最小的宽度

    android:minHeight 最小的高度

    android:maxWidth 最大的宽度

    android:maxHeight 最大的高度

  3. 使用0dp 官方不推荐在ConstraintLayout中使用match_parent,可设置

    0dp(MATCH_CONSTRAINT)配合代替match_parent

    宽高比:当宽或高至少一个被设置为0dp时,可通过属性layout_constraintDimensionRatio设置宽高比还可以在值的前面加上W或者H

    app:layout_constraintDimensionRatio="W,2:1" 宽高比2:1

    app:layout_constraintDimensionRatio="H,2:1" 高宽比2:1

<Button
        android:id="@+id/btn6"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button6"
        android:layout_marginStart="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn5" />

 <!-- 通过layout_constraintDimensionRatio 设置宽高比 -->
    <Button
        android:id="@+id/btn7"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button7"
        app:layout_constraintDimensionRatio="W,2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn6" />
           

效果图:

ConstraintLayout详解

2.6 链

如果两个或以上控件通过下图的方式约束在一起,就可以认为是他们是一条链(图为横向的链,纵向同理)。

ConstraintLayout详解

一条链的第一个控件是这条链的链头,我们可以在链头中设置链的Style,相关的Style有:

app:layout_constraintHorizontal_chainStyle="spread|spread_inside|packed"

app:layout_constraintVertical_chainStyle="spread|spread_inside|packed"

  1. CHAIN_SPREAD : 默认模式(展开元素)
  2. CHAIN_SPREAD_INSIDE :展开元素,两端靠近parent边缘
  3. CHAIN_PACKED :控件被整合在一起
  4. Weighted Chain: 权重链,当宽度或者高度被设置成0dp时,layout_constraintHorizontal_weight 和 layout_constraintVertical_weight控制所占比例

注意:在链中的元素上使用边距时,边距是相加的。A Margin right 10,B Margin left 5,total 15

Style的形式使用下图表示:

ConstraintLayout详解

使用案例:

<Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/btn2" />

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

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button3"
        app:layout_constraintLeft_toRightOf="@id/btn2"
        app:layout_constraintRight_toRightOf="parent" />
           

packed模式:

ConstraintLayout详解

spread模式:

ConstraintLayout详解

spread_inside模式:

ConstraintLayout详解

Weighted Chain模式,必须存在一个0dp:

ConstraintLayout详解

3.辅助工具的使用

3.1 Optimizer

当我们使用 MATCH_CONSTRAINT 时,ConstraintLayout 将对控件进行 2 次测量,ConstraintLayout在1.1中可以通过设置 layout_optimizationLevel 进行优化,可设置的值有:

  1. none 无优化
  2. Standard 仅优化直接约束/屏障约束(默认)
  3. Direct 优化直接约束
  4. Barrier 优化屏障约束
  5. Chain 优化链约束
  6. Dimensions 优化尺寸测量

3.2 Barrier(屏障)

详参:https://developer.android.google.cn/reference/android/support/constraint/Barrier

A与B的宽度未知,现在让C约束在A或者B的右侧都不对;这种情况可用Barrier解决,它相当于在AB的一侧与C之间加了一个屏障。

ConstraintLayout详解

使用Barrier后如下图(A B都在屏障内):

ConstraintLayout详解

主要的属性:

app:barrierDirection="end|top|bottom|start|left|right"

等设置屏障的位置

app:constraint_referenced_ids=””

设置屏障引用的控件,多个值时用’,’隔开

例子:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="15dp"
        android:layout_marginTop="15dp"
        android:text="Button4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="15dp"
        android:layout_marginTop="6dp"
        android:text="Button5 Button5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button1" />

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

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="10dp"
        android:text="为了看到整体的效果,可以切换语言,
        此时你会看到Barrier会自动位于较宽的那个textView后面,
        也就间接让 textView3 也位于了正确的位置"
        app:layout_constraintLeft_toRightOf="@id/barrier"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout详解

最终在C中引用Barrier的约束即可,使用后不管A或者B的宽度如何变化,C始终都位于屏障的右侧

3.3 Group

详参:https://developer.android.google.cn/reference/android/support/constraint/Group

主要作用:把控件归类为一组,更加便捷的管理显示与否等

控件隐藏前:

ConstraintLayout详解

使用Group,并且添加相关的依赖:

app:constraint_referenced_ids="btn2,btn3"关联关系

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintLeft_toRightOf="@id/btn1" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button3"
        app:layout_constraintLeft_toRightOf="@id/btn2" />

    <android.support.constraint.Group
        app:constraint_referenced_ids="btn2,btn3"
        android:visibility="visible"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>
           

控件隐藏后:

ConstraintLayout详解

3.4 Placeholder

详参:https://developer.android.google.cn/reference/android/support/constraint/Placeholder

占位符,可使用setContent设置另一个控件的id,使这个控件移动到占位符的位置.

通过

app:content="@+id/btn1"

属性设置要移动的View

案例:设置Button在右上角,设置Placeholder在左下角,设置content后,Button移动到Placeholder的位置(左下角)

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Placeholder
        android:id="@+id/ph"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:content="@+id/btn1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />


</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout详解
ConstraintLayout详解

3.5 Guideline

详参:https://developer.android.google.cn/reference/android/support/constraint/Guideline

布局辅助线,预览的时候帮助我们完成布局(不显示在界面上)

主要属性:

android:orientation="horizontal|vertical"

app:layout_constraintGuide_end = “50dp”

结束位置

app:layout_constraintGuide_begin = “50dp”

开始位置

app:layout_constraintGuide_percent="0.6"

距离顶部的百分比(orientation = horizontal时则为距离左边)

例子:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <android.support.constraint.Guideline
        android:id="@+id/line1"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

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

    <android.support.constraint.Guideline
        android:id="@+id/line3"
        android:orientation="horizontal"
        app:layout_constraintGuide_end="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout详解

ConstraintLayout 的使用就简单介绍到这里

参考文章