Android ConstraintLayout约束布局的使用

前言:回廊一寸相思地,落月成孤,背灯和月花阴,已是十年踪迹十年心。                                           —— 虞美人

一、概述

AndroidStudio3.0之前默认的根布局是RelativeLayout,但是3.0之后默认的根布局是ConstraintLayout(约束布局),它作为一款强大的调整View位置和大小的ViewGroup被Google所推荐,ConstraintLayout能够以支持库的形式支持到最小的API 9,同时也在不断丰富API和功能,它能在复杂布局中有效降低布局层级,提高性能,使用更加灵活。

但是约束布局不要乱用,因为它在测量子view的相对位置相对大小的时候,它的onmeasure()方法会被多次调用。

我们来探讨一下ConstraintLayout的相关用法,新版的Android Studio在建立工程时会默认添加约束布局的依赖,如果没有添加则需要手动在build.gralde文件中添加依赖库:

implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

二、相关属性

2.1 相对定位

相对定位,其实这个跟RelativeLayout差不多,一个View相对另一个View的位置,常用属性如下:

  • 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_constraintStart_toEndOf                  起始边向尾部对齐;
  • layout_constraintStart_toStartOf                 起始边向起始边对齐;
  • layout_constraintEnd_toStartOf                  尾部向起始边对齐;
  • layout_constraintEnd_toEndOf                   尾部向尾部对齐;
  • layout_constraintBaseline_toBaselineOf    文字的底部线对齐,用于含文本的控件对齐基线;
  • layout_constraintDimensionRatio               宽高比"2:1"、"H,2:1"或"W,2:1"。

我们来简单实用ConstraintLayout来实现下面的布局,tv_1位于水平居中位置,tv_2位于tv_1的右侧,tv_3位于tv_1的下方,

<?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_1"
        android:text="tv_1"
        app:layout_constraintLeft_toLeftOf="parent"  tv_1的左边位于parent(父控件)的左边
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_2"
        app:layout_constraintLeft_toRightOf="@id/tv_1"  tv_2的左边位于tv_1的右边
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_3"
        android:text="tv_3"
        app:layout_constraintLeft_toLeftOf="@id/tv_1"
        app:layout_constraintTop_toBottomOf="@id/tv_1" />

</androidx.constraintlayout.widget.ConstraintLayout>

效果如下:

以tv_3的layout_constraintLeft_toLeftOf="@id/tv_1"来说,layout_constraintLeft表示tv_3的左边,toLeftOf表示tv_1的左边,意思就是说tv_3的左边位于tv_1的左边,如上图tv_3与tv_1左边对齐,那么tv_2的layout_constraintTop_toTopOf="parent"表示tv_2的顶部在parent(父控件)的的顶部。

那么constraintLeft、constraintRight、constraintTop、constraintBottom则分别表示自身控件的左、右、上、下四个位置,toLeftOf、toRightOf、toTopOf、toBottomOf表示位于哪一个控件(后接控件ID)左、右、上、下。大致来说,constrainXXX表示自身的约束边,toXXXOf表示另一个View的边。

那么控件1和控件2文字对齐怎么办,layout_constraintBaseline_toBaselineOf表示文字基线对齐,什么是Baseline,就是文字底部基线

    <TextView
        android:id="@+id/tv_4"
        ......
        android:text="tv_4"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_5"
        ......
        android:text="tv_5"
        app:layout_constraintBaseline_toBaselineOf="@+id/tv_4"
        app:layout_constraintLeft_toRightOf="@id/tv_4" />

效果如下图:

2.2 边距

(1)margin

margin边距和平常使用的没有太大区别,但是要确定View的位置边距才能生效,如果没有确定位置设置边距是没有效果的,下面的tv_6没有确定View的位置,设置了android:layout_margin="20dp"

 <TextView
    android:id="@+id/tv_6"
    ......
    android:layout_margin="20dp"
    android:text="tv_6" />

但是margin并没有生效,效果如下:

那么我们将tv_6的位置确定后,margin就生效了;

 <TextView
    android:id="@+id/tv_6"
    .....
    android:layout_margin="20dp"
    android:text="tv_6"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

tv_6确定在父控件的左上角,margin效果如下:

(2)goneMargin

  • layout_goneMarginLeft         距离目标view左边,当前view与目标view绑定后,目标view设置Gone,当前view的goneMargin属性就会生效。
  • layout_goneMarginRight       距离目标view右边,同上;
  • layout_goneMarginTop         距离目标view上边,同上;
  • layout_goneMarginBottom    距离目标view下边,同上。

ConstraintLayout提供了特殊的layout_goneMarginXXX属性,如果当前view与另一个view绑定后,当前view设置了goneMargin属性,当另一个view设置Gone(隐藏)后,goneMargin属性就会生效。但是注意,goneMargin属性只能作用于另一个view并且作用方向与goneMargin同一方向才会生效;当goneMarginXXX属性生效后,相对于的margin_XXX属性就会失效。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout .....>

    <TextView
        android:id="@+id/tv_7"
        ......
        android:layout_marginLeft="20dp"
        android:text="tv_7"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginTop="20dp" />

    <TextView
        android:id="@+id/tv_8"
        ......
        android:text="tv_8"
        app:layout_constraintLeft_toRightOf="@id/tv_7"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginTop="20dp" />

    <!--tv_9的app:layout_goneMarginLeft="20dp" 在tv_8设置了visibility="gone"才生效,因为tv_9在left方向绑定了tv_8 -->
    <TextView
        android:id="@+id/tv_9"
        ......
        android:text="tv_9"
        android:layout_marginLeft="50dp"
        app:layout_constraintLeft_toRightOf="@id/tv_8"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginLeft="20dp"
        app:layout_goneMarginTop="20dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

tv_7绑定于父控件,tv_8绑定于tv_7,tv_9绑定于tv_8;控件tv_7、tv_8、tv_9中都设置了layout_goneMarginTop="20dp",tv_9中还设置了android:layout_marginLeft="50dp"和 app:layout_goneMarginLeft="20dp"属性,效果如下:

当我们将tv_8设置Gone(隐藏)后,效果如下:

可以看到,只有tv_9中app:layout_goneMarginLeft="20dp"属性生效了,说明当前view(tv_9)于另一个view(tv_8)绑定后,当前view(tv_9)设置了goneMargin属性后,另一个view(tv_8)设置了Gone,当前view(tv_9)的goneMargin属性才会生效。

tv_9中android:layout_marginLeft="50dp"由于找不到tv_8(Gone)所以ayout_marginLeft="50dp"失效了,当tv_8显示后才生效。控件tv_7、tv_8、tv_9中的layout_goneMarginTop="20dp"都没有生效,他们三都是top方向绑定于父控件,所以不会生效。

(3)Centering positioning and bias

ConstraintLayout的居中是采用左右上下边的约束来居中,

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ......>

    <!--垂直居中-->
    <TextView
        ......
        android:text="tv_10"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <!--水平居中-->
    <TextView
        ......
        android:text="tv_11"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--中心-->
    <TextView
        ......
        android:text="tv_12"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

tv_10是垂直居中位置,tv_11是水平居中位置,tv_12是位于视图中间位置,效果如下:

ConstraintLayout也有类似LineraLayout的权重属性,在控件平分的基础上加入bias属性,可以按比例控制距离。

  • layout_constraintHorizontal_bias      水平权重分布,取值范围0-1,0表示最左,1表示最右,0.5表示在中间;
  • layout_constraintVertical_bias           垂直权重分布,取值范围0-1,0表示最上,1表示最下,0.5表示在中间。
  <!--垂直居中 app:layout_constraintHorizontal_bias="0.8"表示水平权重0.8
      tv_13相对于父控件横向偏差剩余空间的80%-->
    <TextView
        ......
        android:text="tv_13"
        app:layout_constraintHorizontal_bias="0.8"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

 <!--水平居中 app:layout_constraintVertical_bias="0.3"表示垂直权重0.3
     tv_14相对于父控件横向偏差剩余空间的30%-->
    <TextView
        ......
        android:text="tv_14"
        app:layout_constraintVertical_bias="0.3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

<!--配合使用,可以根据比例在视图的任何位置-->
    <TextView
        ......
        android:text="tv_15"
        app:layout_constraintVertical_bias="0.3"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

2.3 圆形定位

圆形定位是指View的中心点相对于另外View中心点的位置,设计三个属性:

  • layout_constraintCircle             相对控件ID;
  • layout_constraintCircleAngle    相对角度,逆时针方向,取值范围0~360;
  • layout_constraintCircleRadius  圆的半径,相对控件的中心距离。

  <!--tv_16中心点位于tv_17中心点200dp逆时针45度位置-->
 <TextView
        .....
        android:text="tv_16"
        app:layout_constraintCircle="@id/tv_17"
        app:layout_constraintCircleAngle="45"
        app:layout_constraintCircleRadius="200dp" />

    <TextView
        ......
        android:text="tv_17"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

tv_16中心点位于tv_17中心点200dp逆时针45度位置,效果如下:

2.4 尺寸约束

(1)设置最大最小尺寸

当ConstraintLayout的宽高为warp_content时,可以通过以下属性设置最大最小尺寸,注意宽高为match_parent时不会生效。

  • android:maxWidth         最大宽度;
  • android:maxHeight        最大高度;
  • android:minWidth          最小宽度;
  • android:minHeight         最小高度。

(2)百分比约束

在ConstraintLayout中控件有四种方式制定尺寸大小

  • 指定具体尺寸值,比如100dp;
  • 使用wrap_content,内容自适配;
  • 使用mactch_partent,填充父控件;
  • 设置0dp,即MATCH_CONSTRAINT,拓充可用空间。

第一二三种情况和以前的使用没有区别,但是在ConstraintLayout中不推荐使用mactch_partent,而推荐使用MATCH_CONSTRAINT(0dp),第四种情况会根据控件的约束情况重新计算大小。我们来看看MATCH_CONSTRAINT(0dp)的使用:

 <TextView
        ......
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="tv_18"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

layout_width="0dp",控件与parent左右对齐,控件会横向填充整个父视图空间,效果如下:

在1.1版本之前,控件尺寸设置为warp_content,控件默认由组件文本大小控制,其他约束是不生效的,可以通过以下属性设置是否生效:

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

在1.1版本后,控件设置MATCH_CONSTRAINT(0dp)时,控件大小会拓展所有可用空间,可以通过以下属性改变控件的行为:

  • layout_constraintWidth_default="percent"        指定宽度是默认百分比;
  • layout_constraintWidth_percent="1"                 宽度占parent的百分比,取值范围0-1,百分数形式,1表示 100%;
  • layout_constraintHeight_default                       指定高度是默认百分比;
  • layout_constraintHeight_percent                      高度占parent的百分比,取值范围0-1,百分数形式,1表示 100%;
  • layout_constraintWidth_min                             最小宽度;
  • layout_constraintHeight_min                            最小高度;
  • layout_constraintWidth_max                            最大宽度;
  • layout_constraintHeight_max                           最大高度。

当ConstraintLayout子控件的宽高设置为MATCH_CONSTRAINT,即0dp,可以对宽高设置百分比,例如控件的宽度是屏幕宽度的50%,可以这样处理:

 <!--layout_constraintWidth_default指定按照百分比
    layout_constraintWidth_percent百分比值,控件宽度占父控件的比值-->
    <TextView
        ......
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5"
        android:text="tv_19"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

layout_constraintWidth_default设置为percent,layout_constraintWidth_percent设置为0.5,表示占父控件空间50%,效果如下:

(3)宽高比例约束

控件的宽高比,要求宽或者高至少有一个为0dp,然后设置如下属性,能根据已知值计算另一个值。

  • layout_constraintDimensionRatio       宽高比,比如,如果值为2:1,则表示宽高比例为2:1,如果值为w,2:1,也表示宽高比为2:1,也可以这样写,h,1:2,表示高宽比例为1:2。
  <!--layout_constraintDimensionRatio,指定宽高比,2:1表示宽高比为2:1,
    也可以表示为w,2:1  或者表示为h,1:2  高宽比为1:2 -->
 <TextView
        ......
        android:layout_width="300dp"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

这里宽度为300dp,宽高比为2:1,那么高度为150dp,如下图:

如果宽和高都为0dp,系统会根据实际已知的宽高来计算,比如宽高都为0dp,宽高比例为1:1,但是宽度为屏幕宽度的一半,那么高度也是屏幕宽度的一半,如下图:

  <TextView
        ......
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintWidth_percent="0.5"
        app:layout_constraintDimensionRatio="h,1:1"
        android:text="tv_21"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

2.5 链(chains)

在横轴或竖轴上的控件相互约束时,可以组成一个链式约束,这个属性有点像LinearLayout的weight平分布局。链在水平或者垂直方向提供一组类似行为。

上图为横向链,A与parent的左边缘约束,B与parent的右边缘约束,A的左边与右边之间约束,才能使用一条链。多个元素之间也是如此,最左和最右与parent约束,元素与元素之间约束,不然链式永远无法生效。

横向链最左边的控件,垂直链最顶端的控件称为链头,如下图:

可以通过两个属性链头统一制定链的样式:

  • layout_constraintVertical_chainStyle            水平方向链式;
  • layout_constraintHorizontal_chainStyle        垂直方向链式。

链式的样式的值有几个可选属性:

  • CHAIN_SPREAD                     展开样式,默认为展开;
  • Weighted chain                        在CHAIN_SPREAD 样式,部分控件设置了MATCH_CONSTRAINT,那他们将拓展可用空间;
  • CHAIN_SPREAD_INSIDE       展开样式,但是两端不展开;
  • CHAIN_PACKED                     抱团(打包)样式,控件抱团一起,通过偏移bias,可以改变packed元素的位置。

如下例子:

    <TextView
        ......
        android:text="tv_22"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv_23"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:text="tv_23"
        app:layout_constraintLeft_toRightOf="@id/tv_22"
        app:layout_constraintRight_toLeftOf="@id/tv_24"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:text="tv_24"
        app:layout_constraintLeft_toRightOf="@id/tv_23"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

效果如下:

在链中,剩余空间默认平均给各元素,但是有时可以通过权重属性layout_constraintVertical_weight,来指定分配空间的大小。1.1版本之后,在链中使用边距时,边距是相加的,先除去边距在分配空间的大小。假设tv_22的右边距时10,tv_23的左边距是20,那么他们之间的边距就是30,在链式中,边距先从剩余空间中减去,再用剩余空间在元素之间进行定位。

2.6 优化器

在1.1之后公开了优化器,通过下的属性进行优化

  • layout_optimizationLevel            决定控件在哪方面进行优化。

优化的类型有一下几种:

  • none                    不进行优化;
  • standard              默认方式,仅仅优化direct和direct 约束;
  • direct                   优化direct约束;
  • barrier                 优化barrier约束;
  • chain                   优化链约束;
  • dimensions         优化尺寸,减少测量次数。

三、工具类

3.1 Guideline(参考线)

参考线实际不会在界面显示,只是在布局view的时候做一个参考。可以使用来部分控件与参考线对齐,设置Guideline的orientation来设置参考线是水平方向还是垂直方向,值为verticalhorizontal,可以通过三种方式来定位Guideline的位置:

  • layout_constraintGuide_begin        从左边或者顶部指定的具体距离,水平方向为左右距离,垂直方向为顶部和底部距离;
  • layout_constraintGuide_end           从右边或者底部指定的具体距离;
  • layout_constraintGuide_percent     从开始方向起,占父控件的百分比距离,取值范围0~1,百分比值,比如水平方向,取值0.5,那么参考线在屏幕宽度50%的位置,即屏幕中间。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ......>

    <!--layout_constraintGuide_begin:指定参考线起始位置,下面的控件于参考线对齐-->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="20dp" />

    <TextView
        ......
        android:text="tv_25"
        app:layout_constraintLeft_toLeftOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:text="tv_26"
        app:layout_constraintLeft_toLeftOf="@+id/guideLine"
        app:layout_constraintTop_toBottomOf="@+id/tv_25" />

    <TextView
        ......
        android:text="tv_27"
        app:layout_constraintLeft_toLeftOf="@+id/guideLine"
        app:layout_constraintTop_toBottomOf="@id/tv_26" />

</androidx.constraintlayout.widget.ConstraintLayout>

参考线在左边起20dp的位置,三个控件与参考线左对齐,效果如下

3.2 Barrier(栅栏)

Barrier有点类似Guideline,但是Barrier会根据所引用的控件尺寸变化重新定位,例如登录界面,左边的EditText输入框总洗完与左边的Text提示框最长边缘对齐,两个TextView中的最长那个长度发生变化,Barrier会跟着变化,左边的EditText输入框随之变化。

  • orientation                             Barrier的方向是平方向还是垂直方向,值为verticalhorizontal
  • barrierDirection                     Barrier所引用控件所对齐的位置,有bottom、end、left、right、start、top几个值可选;
  • constraint_referenced_ids    所引用控件的id集合值,例如下面的Barrier以电话号码和密码为引用控件,则输入两个控件的id值,tv_phone,tv_password。

如下图:

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ......>

    <!--orientation: 指定Barrier的方向是平方向还是垂直方向
        barrierDirection: Barrier所引用控件所对齐的位置
        constraint_referenced_ids: 引用控件id集合-->

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

    <TextView
        ......
        android:id="@+id/tv_phone"
        android:text="电话号码"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_password"
        android:text="密码" 
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_phone" />

    <EditText
        ......
        android:id="@+id/et_phone"
        android:hint="请输入手机号码"
        app:layout_constraintLeft_toLeftOf="@+id/barrier" />

    <EditText
        ......
        android:id="@+id/et_password"
        android:hint="请输入密码"
        app:layout_constraintLeft_toLeftOf="@+id/barrier"
        app:layout_constraintTop_toBottomOf="@id/et_phone" />
</androidx.constraintlayout.widget.ConstraintLayout>

3.3 Group (组)

用来控制一组View的可见性,如果View被多个Group控制,则以最后定义的Group可见性为准,

  • constraint_referenced_ids                  需要操作的控件的id集合。

举个例子,tv_28,tv_29,tv_30三个控件,Group控制tv_29,tv_30,Group隐藏前后如下图:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ......>

    <!--Group:用来控制一组view
    constraint_referenced_ids: 存放控件id集合-->
    <androidx.constraintlayout.widget.Group
        android:id="@+id/group"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="tv_29,tv_30" />

    <TextView
        ......
        android:id="@+id/tv_28"
        android:text="tv_28"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv_29"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_29"
        android:text="tv_29"
        app:layout_constraintLeft_toRightOf="@+id/tv_28"
        app:layout_constraintRight_toLeftOf="@+id/tv_30"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_30"
        android:text="tv_30"
        app:layout_constraintLeft_toRightOf="@+id/tv_29"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

效果如下:

3.4 Placeholder(占位符)

一个view的占位符,当指定一个Placeholder的content属性为另一个view的id时,该view本身就会被gone掉,然后装载到Placeholder的位置。相当于把一个View当前位置移动到另外指定的位置。我们来看代码效果吧:

tv_28没有被设置到Placeholder时,显示在左上角;tv_28被设置到Placeholder后,显示在屏幕中央。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ......>

    <!--content:占位符
    content: 替换控件的id-->
    <androidx.constraintlayout.widget.Placeholder
        android:id="@+id/placeholder"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:content="@id/tv_28"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_28"
        android:text="tv_28"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv_29"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_29"
        android:text="tv_29"
        app:layout_constraintLeft_toRightOf="@+id/tv_28"
        app:layout_constraintRight_toLeftOf="@+id/tv_30"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        ......
        android:id="@+id/tv_30"
        android:text="tv_30"
        app:layout_constraintLeft_toRightOf="@+id/tv_29"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

也可以用代码设置:

Placeholder placeholder = findViewById(R.id.placeholder);
placeholder.setContentId(R.id.tv_28);

如下左图,tv_28没有被设置到Placeholder时,下右图,tv_28被设置到Placeholder后

另外ConstraintLayout还能通过拖拽来防止控件的位置,这里就不演示了,可以自己试一下。

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。

我是suming,感谢各位的支持和认可,您的**点赞、评论、收藏**【一键三连】就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

要想成为一个优秀的安卓开发者,这里有必须要掌握的知识架构,一步一步朝着自己的梦想前进!Keep Moving!

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android应用开发 》实验报告 实验序号:04           实验项目名称:微信朋友圈布局页面 "学  号" "姓  名" "专业、班 " " "实验地点" "指导教师" "实验时间 " " "实验目的及要求 " "1、熟悉Eclipse集成开发的步骤; " "2、使用Android制作一个应用程序,实现在屏幕中显示微信朋友圈页面。 " "二、实验设备(环境)及要求 " "1、winXP虚拟机; " "2、Eclipse集成开发环境。 " "三、实验内容与步骤 " "1)在Eclipse中创建Android项目,名称为friends; " "(2)修改新建项目的res/layout目录下的布局文件activity_main.xml,将" "默认添加的布局代码修改为垂直线性布局管理器,并且删除上、下、左、右" "内边距的设置代码,然后将默认添加的文本框组件删除; " "(3)在步骤(2)中添加的垂直线性布局管理器中,添加一个用于显示第一" "条朋友圈信息的相对布局管理器,然后在该布局管理器中添加一个显示头像" "的图像视图组件(ImageView),让它与父容器左对齐; " "(4)在头像ImageView组件的右侧添加3个文本框组件,分别用于显示发布 " "人、内容和时间; " "(5)在内容文本框的下方,与父窗口右对齐的位置添加一个ImageView组件" ",用于显示评论图标; " "(6)在相对布局管理器的下面添加一个ImageView组件,显示一个分隔线;" "(7)按照步骤(3)到步骤(5)的方法添加显示第二条朋友圈信息的代码 " "; " "(8)完成以上操作后,在"包资源管理器"中的项目名称节点上,单击鼠标 " "右键,在弹出的快捷菜单中,选择"运行方式/Android " "Application"菜单项通过模拟器运行程序。 " "四、程序调试(结果及分析) " " " "五、总结与体会 " "通过这次实验,知道了安卓界面布局的各种相关布局方式的,能够使用垂直" "线性布局及相对布局方式,设计"朋友圈"; " "通过这次实验,知道如何向安卓项目中导入图片,以及如何设置各个组件的" "位置,设置文字的颜色,对于安卓项目的页面设计有了更深的认识。 " "六、教师评语 "成绩 " "签名: " " "日期: " " 附关键代码: 1. Xml代码: <?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:orientation="vertical" tools:context=".MainActivity"> <RelativeLayout android:id="@+id/relativeLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" tools:layout_editor_absoluteX="10dp"> <ImageView android:id="@+id/icol" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_margin="10dp" android:src="@drawable/v_ico1" /> <TextView android:id="@+id/name1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_toEndOf="@id/icol" android:text="雪绒花" android:textColor="#576B9
Android Studio的约束布局是一种强大而灵活的布局方式,它允许您以声明性的方式定义视图之间的关系。以下是使用约束布局的一些基本步骤: 1. 在布局文件中使用`ConstraintLayout`作为根视图。在XML文件中,您可以这样声明一个约束布局: ``` <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"> <!-- 在这里添加其他视图 --> </androidx.constraintlayout.widget.ConstraintLayout> ``` 2. 定义视图之间的约束关系。您可以通过拖动和放置视图来在设计编辑器中设置约束,也可以在XML文件中手动编写约束。例如,要将一个按钮位于父布局顶部,并与左右边缘有10dp的间距,您可以这样定义约束: ``` <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="My Button" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_marginStart="10dp" app:layout_marginEnd="10dp"/> ``` 3. 可选地,您还可以使用链(chains)和辅助对象(guidelines)来进一步定义视图之间的关系,以及在不同屏幕尺寸下的自适应布局约束布局的优势在于它可以适应各种屏幕尺寸和方向,并且可以减少嵌套布局的需要。您可以通过在Android Studio的设计编辑器中直观地操作视图和约束,或者手动编辑XML文件来创建约束布局。要了解更多关于约束布局的信息和用法,请参阅Android官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值