ConstraintLayout约束性布局攻略

2,730 阅读4分钟

开发指南

  1. Relative positioning 相对位置 相对位置是ConstrainLayout中创建布局的基础构建块之一,这些约束允许你定位一个部件相对于另外一个的位置,你可以在水平和垂直轴上约束部件。

水平:left, right, start, end

垂直:top, bottom, text baseline

根据其他控件给自身定位:

layout_toRightOf="A"——>layout_constraintLeft_toRightOf="A"

根据父容器给自身定位:

layout_alignParentRight=true——>layout_constraintRight_toRightOf=parent

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

开始我的实践


<?xml version="1.0" encoding="utf-8"?>
<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="match_parent"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20"
        android:textColor="@color/black"
        android:textSize="50sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="¥"
        android:textColor="@color/black"
        android:textSize="20sp"
        app:layout_constraintBaseline_toBaselineOf="@id/tv1"
        app:layout_constraintStart_toEndOf="@id/tv1" />

</androidx.constraintlayout.widget.ConstraintLayout>


image.png

  <TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
  />

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text2"
    android:gravity="center"
    android:text="text2"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@id/text1"
    app:layout_constraintTop_toBottomOf="@id/text1"
  />

上面代码中在TextView2里用到了app:layout_constraintLeft_toRightOf="@id/text1"这个属性,他的意思是把TextView2的左边约束到TextView1的右边 ,app:layout_constraintTop_toBottomOf="@id/text1" ,TextView2的顶部约束到TextView1的底部。

app:layout_constraintBottom_toBottomOf="parent" 控件在屏幕底部

两个TextView的高度不一致,但是又希望他们文本对齐,这个时候就可以使用layout_constraintBaseline_toBaselineOf,代码如下:

 <TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
  />

<TextView
    android:layout_width="100dp"
    android:layout_height="50dp"
    android:id="@+id/text2"
    android:gravity="center"
    android:text="text2"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@id/text1"
    app:layout_constraintBaseline_toBaselineOf="@id/text1"
  />

  1. Margins 边距

android:layout_marginStart android:layout_marginEnd android:layout_marginLeft android:layout_marginTop android:layout_marginRight android:layout_marginBottom

Margins属性需要和constraintXXX_toXXX属性配套使用才生效,当相对部件不可见时,Margins属性同样生效

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    android:layout_marginLeft="20dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
  />

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text2"
    android:gravity="center"
    android:text="text2"
    app:layout_goneMarginLeft="20dp"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@id/text1"
    app:layout_constraintTop_toTopOf="@id/text1"
  />

当TextView1为gone是app:layout_goneMarginLeft="20dp" 生效

3 居中和偏移

 <TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    android:layout_marginLeft="20dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    />

ConstraintLayout还提供了另外一种偏移的属性: layout_constraintHorizontal_bias 水平偏移 layout_constraintVertical_bias 垂直偏移

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    android:layout_marginLeft="20dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_bias="0.3"
    />

Circular positioning (Added in 1.1)环形位置可以以角度和距离约束一个部件的中心,相对于另一个部件的中心位置,即相对于另一个部件中心的圆形上。

layout_constraintCircle 另一个部件ID

layout_constraintCircleRadius 半径

layout_constraintCircleAngle 角度 (from 0 to 360)

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text1"
    android:text="text1"
    android:background="@color/blue"
    android:gravity="center"
    android:layout_marginLeft="20dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    />

<TextView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/text2"
    android:gravity="center"
    android:text="text2"
    app:layout_constraintCircle ="@id/text1"
    app:layout_constraintCircleRadius="150dp"
    app:layout_constraintCircleAngle ="150"
    app:layout_goneMarginLeft="20dp"
    android:background="@color/qmui_config_color_red"
    tools:ignore="MissingConstraints" />

宽高比 当宽或高至少有一个尺寸被设置为0dp时,可以通过属性layout_constraintDimensionRatio设置宽高比,举个例子:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintDimensionRatio="1:1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent" />
    

复制代码宽设置为0dp,宽高比设置为1:1,这个时候TextView1是一个正方形,效果如下:

除此之外,在设置宽高比的值的时候,还可以在前面加W或H,分别指定宽度或高度限制。 例如:

app:layout_constraintDimensionRatio="H,2:3"指的是 高:宽=2:3

app:layout_constraintDimensionRatio="W,2:3"指的是 宽:高=2:3

4权重比使用

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="100dp"
    android:text="TextView1"
    android:background="@color/green"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/TextView2"
    app:layout_constraintHorizontal_weight="2" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="0dp"
    android:layout_height="100dp"
    android:text="TextView2"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="3" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="0dp"
    android:text="TextView3"
    android:background="@color/blue"
    android:layout_height="100dp"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="4" />

layout_constraintHorizontal_chainStyle来改变整条链的样式。chains提供了3种样式,分别是: CHAIN_SPREAD —— 展开元素 (默认); CHAIN_SPREAD_INSIDE —— 展开元素,但链的两端贴近parent; CHAIN_PACKED —— 链的元素将被打包在一起。 如图所示:

 <TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:text="TextView1"
    android:background="@color/green"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/TextView2"
    app:layout_constraintHorizontal_chainStyle="spread_inside"
   />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:text="TextView2"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_chainStyle="spread_inside"
    />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:text="TextView3"
    android:background="@color/blue"
    android:layout_height="100dp"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_chainStyle="spread_inside"
    />

CHAIN_SPREAD_INSIDE —— 展开元素

CHAIN_PACKED

5 WRAP_CONTENT enforcing constraints (Added in 1.1) 在1.1前,设置wrap_content属性,会被视为文字尺寸,即约束不会限制结果尺寸。通常这已经足够(更快)。有些情况,仍然希望强制执行约束限制结果尺寸,这种情况,可以使用新的属性。

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

<TextView
    android:id="@+id/TextView1"
    android:layout_width="150dp"
    android:layout_height="150dp"
    android:text="TextView1"
    android:background="@color/green"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"

   />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:text="TextView2TextView2TextView2TextView2TextView2TextView2TextView2TextView2TextView2"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toRightOf="parent"
    
    />

<!-- 增加app:layout_constrainedWidth="true"属性后 -->

 <androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_begin="172dp" />

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:layout_marginTop="15dp"
    android:background="@color/cardview_dark_background"
    android:text="TextViTexew"
    app:layout_constraintEnd_toStartOf="@+id/textView2"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/guideline" />

<TextView
    android:id="@+id/textView2"
    android:layout_width="0dp"
    android:layout_height="100dp"
    android:layout_marginLeft="15dp"

    android:layout_marginTop="15dp"
    android:background="@color/design_default_color_primary"
    android:text="aaaaaaaaaaaaaaaaaaa"
    app:layout_constraintEnd_toStartOf="@+id/textView3"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toEndOf="@+id/textView"
    app:layout_constraintTop_toBottomOf="@+id/guideline" />

<TextView
    android:id="@+id/textView3"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:layout_marginStart="15dp"
    android:layout_marginTop="15dp"
    android:background="@color/cardview_shadow_start_color"
    android:text="TextView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toEndOf="@+id/textView2"
    app:layout_constraintTop_toBottomOf="@+id/guideline" />

6 辅助工具

Barrier

假设有3个控件ABC,C在AB的右边,但是AB的宽是不固定的,这个时候C无论约束在A的右边或者B的右边都不对。当出现这种情况可以用Barrier来解决。Barrier可以在多个控件的一侧建立一个屏障,如下所示:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@color/green"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

<TextView
    android:id="@+id/TextView2"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="@color/qmui_config_color_red"
    app:layout_constraintTop_toBottomOf="@id/TextView1"
    app:layout_constraintLeft_toLeftOf="@id/TextView1"/>

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="right"
    app:constraint_referenced_ids="TextView1,TextView2" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:background="@color/yellow"
    android:text="我爱你爱着你就像老鼠爱大米,我爱你爱着你就像老鼠爱大米"
    app:layout_constrainedWidth="true"
    app:layout_constraintLeft_toRightOf="@+id/barrier"
    app:layout_constraintRight_toRightOf="parent"/>

Group可以把多个控件归为一组,方便隐藏或显示一组控件,举个例子:

<androidx.constraintlayout.widget.Group
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="invisible"
    app:constraint_referenced_ids="TextView1,TextView3" />

MATCH_CONSTRAINT尺寸(在1.1中添加)

当一个view的长宽设置为MATCH_CONSTRAINT(即0dp)时,默认是使该view占用所有的可用的空间. 这里有几个额外的属性

layout_constraintWidth_min和layout_constraintHeight_min:将设置此维度的最小大小
layout_constraintWidth_max和layout_constraintHeight_max:将设置此维度的最大大小
layout_constraintWidth_percent和layout_constraintHeight_percent:将此维度的大小设置为父级的百


 <Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Q"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.5"/>

Guideline可以创建相对于ConstraintLayout的水平或者垂直准线. 这根辅助线,有时候可以帮助我们定位.

layout_constraintGuide_begin   距离父亲起始位置的距离(左侧或顶部)
layout_constraintGuide_end    距离父亲结束位置的距离(右侧或底部)
layout_constraintGuide_percent    距离父亲宽度或高度的百分比(取值范围0-1)

复制代码我们拿辅助线干嘛??? 比如有时候,可能会有这样的需求,有两个按钮,在屏幕中央一左一右. 如果是以前的话,我会搞一个LinearLayout,.然后将LinearLayout居中,然后按钮一左一右.

<!--水平居中-->
<android.support.constraint.Guideline
android:id="@+id/gl_center"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintEnd_toStartOf="@id/gl_center"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2"
app:layout_constraintLeft_toRightOf="@id/gl_center"/>