ConstraintLayout使用详解

ConstraintLayout 是 Android Studio 2.2 中主要的新增功能之一,也是 Google 在2016 年的 I/O 大会上重点宣传的一个功能。ConstraintLayout 是使用约束的方式来指定各个控件的位置和关系的,相比 RelativeLayout 和 LineatLayout 具有更强的特性,可以减少布局之间的嵌套。

1. 添加 ConstraintLayout

在工程app目录下的 build.gradle 添加如下:

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
}

2. 相对位置属性

layout_constraint[自身控件位置]_[目标控件位置]="[目标控件ID]",如果id是父布局的id,可以使用parent

<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
              app:layout_constraintLeft_toRightOf="@+id/buttonA" />

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

3. Margin属性

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

4. goneMargin属性

goneMargin属性是指目标控件GONE掉之后,自身控件可以设置个margin值。不过margin的方向需要和控件的相对位置的方向保持一致。

假设我们有这样一个需求:A设置为gone后,B需要距离父布局的左侧200dp,怎么办?这时候,goneMargin属性就派上用场啦,只要设置B的layout_goneMarginLeft=200dp即可。这样,A为gone时,B距离父布局左侧200dp。

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

5. Bias属性

bias属性是指在对齐父容器后,设置水平与竖直的比例。bias支持的属性如下:

layout_constraintHorizontal_bias
layout_constraintVertical_bias

<androidx.constraintlayout.widget.ConstraintLayout ...>
             <Button android:id="@+id/button" ...
                 app:layout_constraintHorizontal_bias="0.3"
                 app:layout_constraintLeft_toLeftOf="parent"
                 app:layout_constraintRight_toRightOf="parent/>
         </>

6. Ratio属性

layout_constraintDimensionRatio,通过该属性可以设置View的高宽比。

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

    <!--指定高度,宽度随着宽高比自适应 -->
    <!--app:layout_constraintDimensionRatio="16:9"  W: 默认,表示宽高比-->
    <TextView
        android:id="@+id/text_01"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:background="#B0E46E"
        android:text="text_01"
        app:layout_constraintDimensionRatio="16:9"
        app:layout_constraintLeft_toLeftOf="parent" />

    <!--指定高度,宽度随着宽高比自适应 -->
    <!--app:layout_constraintDimensionRatio="H,16:9"  H: 表示高宽比-->
    <TextView
        android:id="@+id/text_02"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:background="#AA4727"
        android:text="text_02"
        app:layout_constraintDimensionRatio="H,16:9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_01" />

    <!--指定宽度,按照宽度来计算高宽比,默认是宽高比 -->
    <TextView
        android:id="@+id/text_03"
        android:layout_width="60dp"
        android:layout_height="0dp"
        android:background="#F6BE4F"
        android:text="text_03"
        app:layout_constraintDimensionRatio="16:9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_02" />

    <!--指定宽度,按照宽度来计算高宽比  W:表示高宽比 -->
    <TextView
        android:id="@+id/text_04"
        android:layout_width="60dp"
        android:layout_height="0dp"
        android:background="#CA4B45"
        android:text="text_04"
        app:layout_constraintDimensionRatio="W,16:9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_03" />

    <!--android:layout_width="0dp"  0dp表示充满父控件或说是充满其余空间-->
    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#CFDEF9"
        android:text="text_05"
        app:layout_constraintDimensionRatio="3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_04" />

</androidx.constraintlayout.widget.ConstraintLayout>

运行图,如下:

7. Chains 链状结构

如下图:

要想Chain Style生效,必须设置当前链方向的边为wrap_content,比如上面的水平链,宽设为wrap_content。还有就是控件要相互引用,比如A的右边依赖B的左边,B的左边依赖A的右边。

Chain Style 设置在第一个控件上 。

属性有两个:

layout_constraintHorizontal_chainStyle
layout_constraintVertical_chainStyle

支持的值有三个:

CHAIN_SPREAD:均匀分布控件。
CHAIN_SPREAD_INSIDE,同上,但是边上的控件不均匀分布。
CHAIN_PACKED:控件紧挨在一起,还可以通过bias属性设置偏移量。

Weighted chains:

app:layout_constraintHorizontal_weight
app:layout_constraintVertical_weight

跟线性布局的weight差不多,layout_constraintHorizontal_weight需要设置width=0dp,控件的大小根据设置的weight比例进行设置。

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

    <TextView
        android:id="@+id/tv_bottom_01"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:background="#F67"
        android:gravity="center"
        android:text="首页"
        android:textColor="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv_bottom_02" />

    <TextView
        android:id="@+id/tv_bottom_02"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:background="#A67"
        android:gravity="center"
        android:text="圈子"
        android:textColor="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toRightOf="@+id/tv_bottom_01"
        app:layout_constraintRight_toLeftOf="@+id/tv_bottom_03" />

    <TextView
        android:id="@+id/tv_bottom_03"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:background="#767"
        android:gravity="center"
        android:text="我的"
        android:textColor="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toRightOf="@id/tv_bottom_02"
        app:layout_constraintRight_toRightOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

运行图,如下:

8. Guideline

android.support.constraint.Guideline 该类比较简单,主要用于辅助布局,即类似为辅助线,横向的、纵向的。该布局是不会显示到界面上的。

所以其有个属性为:

android:orientation="vertical"
android:orientation="horizontal"

除此以外,还差个属性,决定该辅助线的位置:

layout_constraintGuide_begin
layout_constraintGuide_end
layout_constraintGuide_percent

可以通过上面3个属性其中之一来确定属性值位置。

begin=30dp,即可认为距离顶部30dp的地方有个辅助线,根据orientation来决定是横向还是纵向。
end=30dp,即为距离底部。
percent=0.8即为距离顶部80%。

比如:有个按钮,决定通过两根辅助线来定位,一根横向距离底部80%,一个纵向距离顶部80%,按钮就定位在他们交叉的地方。

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.Guideline
        android:id="@+id/guideline_h"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.8" />

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

    <TextView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="#612"
        app:layout_constraintLeft_toRightOf="@id/guideline_w"
        app:layout_constraintTop_toBottomOf="@id/guideline_h" />

</androidx.constraintlayout.widget.ConstraintLayout>

运行图,如下:

  • 注意ConstraintLayout不支持match_parent属性,要用0dp代替,在加上设置特性的约束属性,即可实现match_parent的效果。

ConstraintLayout官方文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容