今天看啥  ›  专栏  ›  XingJimmy

ConstraintLayout约束性布局攻略

XingJimmy  · 掘金  ·  · 2019-09-23 09:53
阅读 22

ConstraintLayout约束性布局攻略

介绍

ConstraintLayout是可以灵活定位、调整小部件的ViewGroup,API9开始支持的Support库,用来解决布局嵌套过多的问题。 developer.android.com/reference/a…

developer.android.com/training/co…

开发指南

1. Relative positioning 相对位置

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

  • 水平:left, right, start, end

  • 垂直:top, bottom, text baseline

    下面是可用约束的列表

    他们都支持引用另一个部件的id或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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintRight_toLeftOf="@id/txtA"
        app:layout_constraintBottom_toTopOf="@id/txtA"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

2. Margins 边距

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

Margins属性需要和constraintXXX_toXXX属性配套使用才生效

当相对部件不可见时,Margins属性同样生效

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        android:layout_marginLeft="20dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@android:color/holo_red_light"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintRight_toLeftOf="@id/txtA"
        app:layout_constraintBottom_toTopOf="@id/txtA"
        android:background="@android:color/holo_green_light"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

以上,txtA设置layout_marginLeft属性,没有效果。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@android:color/holo_red_light"/>
    <TextView
        android:id="@+id/txtB"
        ......
        android:layout_marginRight="20dp"
        app:layout_constraintRight_toLeftOf="@id/txtA"
        app:layout_constraintBottom_toTopOf="@id/txtA"
        android:background="@android:color/holo_green_light"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

以上,txtB设置layout_marginRight属性,有效果。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        android:visibility="gone"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@android:color/holo_red_light"/>
    <TextView
        android:id="@+id/txtB"
        ......
        android:layout_marginRight="20dp"
        app:layout_constraintRight_toLeftOf="@id/txtA"
        app:layout_constraintBottom_toTopOf="@id/txtA"
        android:background="@android:color/holo_green_light"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

以上,txtA不可见后,txtB的layout_marginRight属性仍然生效。

Margins 相对不可见View的边距。View可见时,不生效

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

先看下View可见的效果

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        android:visibility="visible"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_goneMarginRight="20dp"
        app:layout_constraintRight_toLeftOf="@id/txtA"
        app:layout_constraintBottom_toTopOf="@id/txtA"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

下面看下View不可见的效果
可见,右侧是有边距的。

3. 居中位置,parent也可以改成其他View的id值

  • 水平居中
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
复制代码
  • 垂直居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
复制代码

4. Bias 偏移

相反约束默认是使部件居中显示,即偏移50%,可以通过Bias属性来改变偏差

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3"
复制代码

5. Circular positioning (Added in 1.1) 环形位置

可以以角度和距离约束一个部件的中心,相对于另一个部件的中心位置,即相对于另一个部件中心的圆形上。

  • layout_constraintCircle 另一个部件ID
  • layout_constraintCircleRadius 半径
  • layout_constraintCircleAngle 角度 (from 0 to 360)

6. Visibility behavior 可见行为

ConstraintLayout中的Widgets,如果设置Gone。虽然不可见,但大小会变成0的占位。可以用来做动画基础。

7. Dimensions constraints 尺寸约束

7.1 Minimum dimensions on ConstraintLayout ConstraintLayout最小尺寸

  • android:minWidth set the minimum width for the layout
  • android:minHeight set the minimum height for the layout
  • android:maxWidth set the maximum width for the layout
  • android:maxHeight set the maximum height for the layout

这些属性是设置在ConstraintLayout,且设置wrap_content。

7.2 Widgets dimension constraints 部件尺寸约束

设置android:layout_width和android:layout_height属性值指定控件的尺寸。

  • 使用指定数值
  • 使用wrap_content 要求控件自己计算自己的大小
  • 使用0dp 相当于match_constraint

重要: MATCH_PARENT不推荐使用. 可以使用MATCH_CONSTRAINT。

7.3 WRAP_CONTENT enforcing constraints (Added in 1.1)

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

  • app:layout_constrainedWidth="true|false"
  • app:layout_constrainedHeight="true|false"
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:background="@android:color/holo_red_light"/>
    <TextView
        android:id="@+id/txtB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
        ......
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        android:background="@android:color/holo_green_light"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

以上,同时约束左侧、右侧的情况。可见,约束没有起作用。

<!-- 增加app:layout_constrainedWidth="true"属性后 -->
复制代码

8. Ratio 宽高比例

8.1 设置宽、高中一个属性值为0dp。

非0的属性值,根据Radio设置值为0dp的属性值

取值:

  • 浮点值,表示宽度和高度之间的比率(比如:1.0F)
  • "宽度:高度"形式的比率(比如:1:1)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        android:layout_width="160dp"
        android:layout_height="0dp"
        ......
        app:layout_constraintDimensionRatio="1.0"/>
    <TextView
        android:id="@+id/txtB"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:text="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
        ......
        app:layout_constraintDimensionRatio="1:1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

8.2 宽、高属性都设置成0dp

满足所有约束的最大尺寸并保持指定的比例,要根据某一个特定边的尺寸限制另一个特定边,可以预先附加W 或 H,表示想要约束的宽度或高度。

app:layout_constraintDimensionRatio="W,1:1"
复制代码

9. Chains

链在单个轴上提供一组相似行为(水平或垂直),另一个轴独立约束。

9.1 Creating a chain 创建

一组控件通过双向链接,连接在一起,则被视为链。

错误代码示例

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

以上,可以理解成,是B对A的单向链。A并没有链接到B上。

正确代码示例

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

9.2 Chain heads 链头

链由第一个元素(链头)的属性控制。 链头,水平链的最左侧,垂直链的最顶部。

9.4 Chain Style 样式

  • layout_constraintHorizontal_chainStyle
  • layout_constraintVertical_chainStyle

取值:

  • spread -- 默认,元素将展开,居中均分展示。
  • spread权重模式 -- spread模式下,控件设置成0dp,则会分割可用空间。
  • spread_inside -- 类似spread模式,两端控件靠边,其他居中均分展示。
  • packed -- 链中所有元素,作为一个整体,默认居中,水平或垂直偏差,通过属性Bias控制。
  • spread
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC"/>
    <TextView
        android:id="@+id/txtC"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

  • spread权重模式
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC" />
    <TextView
        android:id="@+id/txtC"
        android:layout_width="0dp"
        android:layout_height="120dp"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

可见,WidgetC宽度占了全部剩余空间

如果有多个控件设置了0dp,可以通过属性控制各自权重值

  • app:layout_constraintHorizontal_weight
  • app:layout_constraintVertical_weight
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        android:layout_width="0dp"
        android:layout_height="150dp"
        ......
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC" />
    <TextView
        android:id="@+id/txtC"
        android:layout_width="0dp"
        android:layout_height="120dp"
        ......
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

  • spread_inside
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC" />
    <TextView
        android:id="@+id/txtC"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

  • packed
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC" />
    <TextView
        android:id="@+id/txtC"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/txtA"
        ......
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/txtB"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txtB"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtA"
        app:layout_constraintRight_toLeftOf="@id/txtC" />
    <TextView
        android:id="@+id/txtC"
        ......
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/txtB"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

10. 辅助布局

developer.android.google.cn/reference/a…?

  • Barrier
  • ConstraintSet
  • Group
  • Guideline
  • PlaceHolder



原文地址:访问原文地址
快照地址: 访问文章快照