约束布局ConstraintLayout 使用

ConstraintLayoutRelativeLayout 相似,其中所有的视图均根据同级视图与父布局之间的关系进行布局,但其灵活性要高于 RelativeLayout,适合创建复杂的大型布局。

官方教程地址:https://developer.android.google.cn/training/constraint-layout

一、基本使用

1.1 添加到项目中

  1. 在项目根目录的 build.gradle文件中声明:

        repositories {
            google()
        }
        
    
  2. 将该库作为依赖项添加到项目的 build.gradle 文件中,如以下示例所示

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.0.4"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha07"
    }
    

1.2 基本使用

约束条件如下:


未命名文件.png

例如下面这个简单的布局,有个按钮位于屏幕左上角


布局1.png

对应的布局代码如下:

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

  <Button
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="test"/>
</androidx.constraintlayout.widget.ConstraintLayout>

其中 parent 代表的是父布局。

注意:在约束性布局中,除非宽高设置成 match_parent,否则其他场景都需要设置 (上 || 下)&& (左 || 右) 的约束条件, 不然编译器会出现报错警告。

二、布局居中

水平居中:


水平居中.png

设置 constraintLeftconstraintRight,根据左右两边约束的视图居中。

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

  <Button
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="test"/>
</androidx.constraintlayout.widget.ConstraintLayout>

垂直居中:


竖直居中.png

设置 constraintTopconstraintBottom,根据上下约束的视图居中。

  <Button
    android:id="@+id/btn"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="test"/>

居中设置偏移比例

设置 layout_constraintVertical_biaslayout_constraintHorizontal_bias

layout_constraintVertical_bias:垂直偏移,范围 0 ~ 1 ,0代表最上方,1代表最下方

layout_constraintHorizontal_bias:水平偏移,范围 0 ~ 1,0代表最左边,1代表最右边

水平偏移.png
垂直偏移.png

三、链条控制线性组

设置 layout_constraintHorizontal_chainStylelayout_constraintVertical_chainStyle 通过链条方式控制一组控件,例如:

链条.png

1 Spread:视图均匀分布,默认该属性

2 Packed:视图打包一起

3 Spread inside:第一个和最后一个视图固定在链条两端

4 Weighted:权重布局,layout_width = 0dp,layout_constraintHorizontal_weight设置权重

链是一组视图,这些视图通过 双向位置约束条件相互链接到一起,即上图 链中的视图可以垂直或水平分布。
由链条的第一个视图设置 chainStyle 即可。

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

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

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

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

  <Button
    android:id="@+id/btn4"
    android:layout_marginTop="64dp"
    app:layout_constraintTop_toBottomOf="@id/btn1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@id/btn5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="btn4"
    app:layout_constraintHorizontal_chainStyle="packed"/>

  <Button
    android:id="@+id/btn5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/btn4"
    app:layout_constraintRight_toLeftOf="@id/btn6"
    app:layout_constraintTop_toTopOf="@id/btn4"
    android:text="btn5"/>

  <Button
    android:id="@+id/btn6"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/btn5"
    app:layout_constraintTop_toTopOf="@id/btn4"
    app:layout_constraintRight_toRightOf="parent"
    android:text="btn6"/>

  <Button
    android:id="@+id/btn7"
    android:layout_marginTop="64dp"
    app:layout_constraintTop_toBottomOf="@id/btn4"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@id/btn8"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="btn7"
    app:layout_constraintHorizontal_chainStyle="spread_inside"/>

  <Button
    android:id="@+id/btn8"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/btn7"
    app:layout_constraintRight_toLeftOf="@id/btn9"
    app:layout_constraintTop_toTopOf="@id/btn7"
    android:text="btn8"/>

  <Button
    android:id="@+id/btn9"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/btn8"
    app:layout_constraintTop_toTopOf="@id/btn7"
    app:layout_constraintRight_toRightOf="parent"
    android:text="btn9"/>

  <Button
    android:id="@+id/btn10"
    android:layout_marginTop="64dp"
    app:layout_constraintTop_toBottomOf="@id/btn7"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@id/btn11"
    android:layout_width="0dp"
    app:layout_constraintHorizontal_weight="1"
    android:layout_height="wrap_content"
    android:text="btn10"
    app:layout_constraintHorizontal_chainStyle="spread_inside"/>

  <Button
    android:id="@+id/btn11"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintHorizontal_weight="2"
    app:layout_constraintLeft_toRightOf="@id/btn10"
    app:layout_constraintRight_toLeftOf="@id/btn12"
    app:layout_constraintTop_toTopOf="@id/btn10"
    android:text="btn11"/>

  <Button
    android:id="@+id/btn12"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintHorizontal_weight="2"
    app:layout_constraintLeft_toRightOf="@id/btn11"
    app:layout_constraintTop_toTopOf="@id/btn10"
    app:layout_constraintRight_toRightOf="parent"
    android:text="btn12"/>
</androidx.constraintlayout.widget.ConstraintLayout>

四、引导线约束

可以添加垂直或水平的引导线来约束视图,并且应用用户看不到该引导线。 可以根据相对于布局边缘的 dp 单位或百分比在布局中定位引导线。


引导线.png
  <androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintGuide_percent="0.5"/>

  <Button
    android:id="@+id/btn1"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:layout_width="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/guideline"
    android:layout_height="wrap_content"
    android:text="btn1"/>

引导线也是一个控件,只是不会显示出来,orientation 设置垂直或水平方向的引导线,layout_constraintGuide_percent 支持百分比定位引导线,范围 0 ~ 1。

由于 layout_margin 无法设置百分比,我们可以通过 Guideline 替代实现。

五、实现覆盖布局效果

覆盖1.png

上图这种覆盖方式通过布局顺序实现的,btn2 控件布局中在 btn1 控件的下方。

由于 ConstraintLayout 布局中无法设置负数的 margin ,所以如果想覆盖控件的上半部分,可以通过引导线等辅助实现。

覆盖2.png

<androidx.constraintlayout.widget.Guideline
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.5"
    android:id="@+id/space"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

  <Button
    android:background="@color/colorAccent"
    android:layout_marginTop="32dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn1"
    android:text="btn1"
    app:layout_constraintTop_toBottomOf="@id/space"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"/>

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn2"
    android:text="btn2"
    android:layout_marginStart="64dp"
    android:background="@color/reset_totp_indicator_color"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@id/space"/>

六、百分比布局

layout_constraintHeight_percentlayout_constraintWidth_percent 支持通过百分比设置控件的宽高,范围 0 ~ 1 。

百分比.png

  <Button
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:text="btn1"
    app:layout_constraintHeight_percent="0.3"
    app:layout_constraintWidth_percent="0.5"
    android:background="@color/reset_totp_indicator_color"/>

layout_widthlayout_height 必须设置成 0dp,才可以生效。

七、约束失效问题

当设置 wrap_content 再设置约束条件时会发现约束条件失效了,例如:

约束失效.png

 <TextView
    android:text="sdfsfdsdfsdfssdfsdfsdfdsfdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdf"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/tv_username"
    android:textColor="@color/find_pass_text_color"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@id/btn1"
    android:maxLines="1"
    android:ellipsize="end"
    app:layout_constraintHorizontal_chainStyle="packed"
    app:layout_constraintHorizontal_bias="0"
    />

  <Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:text="btn1"
    app:layout_constraintHeight_percent="0.3"
    app:layout_constraintWidth_percent="0.5"
    android:background="@color/colorAccent"/>

虽然设置了约束条件 app:layout_constraintRight_toLeftOf="@id/btn1",但实际并没有生效。

需要设置 layout_constrainedWidth 为true,修改后效果如下:

约束失效2.png

  <TextView
    android:text="sdfsfdsdfsdfssdfsdfsdfdsfdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdf"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/tv_username"
    android:textColor="@color/find_pass_text_color"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@id/btn1"
    android:maxLines="1"
    android:ellipsize="end"
    app:layout_constraintHorizontal_chainStyle="packed"
    app:layout_constraintHorizontal_bias="0"
    app:layout_constrainedWidth="true"
    />

  <Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:text="btn1"
    app:layout_constraintHeight_percent="0.3"
    app:layout_constraintWidth_percent="0.5"
    android:background="@color/colorAccent"/>

八、设置视图最大、最小尺寸

有时候适配不同屏幕时,我们不希望尺寸随着屏幕变大而无限拉伸,这时候可以通过 layout_constraintWidth_maxlayout_constraintHeight_maxlayout_constraintWidth_minlayout_constraintHeight_min 这几个设置宽高的最大或最小值。

需要配合百分比布局 layout_constraintWidth_percent 才可以生效。

限制宽高1.png
  <Button
    android:id="@+id/btn1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    android:text="btn1"
    android:background="@color/colorAccent"
    app:layout_constraintWidth_percent="0.85"
    />

设置宽度最大值为 200dp,修改后显示如下:


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

推荐阅读更多精彩内容