Android-ConstraintLayout约束布局使用

2020-11-13  本文已影响0人  zzq_nene

一、ConstraintLayout基础属性详解

属性 描述
app:layout_constraintLeft_toLeftOf 把A的left side放在B的left side(左边对齐)
app:layout_constraintLeft_toRightOf 把A的left side放在B的right side(左边相对右边对齐)
app:layout_constraintRight_toLeftOf 把A的right side放在B的left side(右边相对左边对齐)
app:layout_constraintRight_toRightOf 把A的right side放在B的right side(右边对齐)
app:layout_constraintTop_toTopOf 把A的top side放在B的top side(顶部对齐)
app:layout_constraintTop_toBottomOf 把A的top side放在B的bottom side(顶部相对底部对齐)
app:layout_constraintBottom_toTopOf 把A的bottom side放在B的top side(底部相对顶部对齐)
app:layout_constraintBottom_toBottomOf 把A的bottom side放在B的bottom side(底部对齐)
app:layout_constraintStart_toEndOf 把A的start position放在B的end position(起始位置相对结束位置对齐)
app:layout_constraintStart_toStartOf 把A的start position放在B的start position(起始位置对齐)
app:layout_constraintEnd_toStartOf 把A的end position放在B的start position(结束位置相对起始位置对齐)
app:layout_constraintEnd_toEndOf 把A的end position放在B的end position(结束位置对齐)
app:layout_constraintBaseline_toBaselineOf 把A的bottom side放在B的top side(基准线对齐)

这里分别以:app:layout_constraintLeft_toLeftOf和app:layout_constraintRight_toLeftOf举例:
定义两个控件:

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/right_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_1"
        android:gravity="center"
        android:text="右上角"
        android:textSize="32sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:id="@+id/where"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我在哪里"
        android:background="#ff0000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="@+id/right_top"/>
</androidx.constraintlayout.widget.ConstraintLayout>

这里的id为where的TextView就使用了app:layout_constraintLeft_toLeftOf相对于另一个TextView,这个时候id为where的TextView的显示的位置,其实是左边贴在了id为right_top的TextView的左边上。如下图:


image.png

这个时候如果将id为where的相对于id为right_top的修改成app:layout_constraintRight_toLeftOf,如下所示:

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/right_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_1"
        android:gravity="center"
        android:text="右上角"
        android:textSize="32sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:id="@+id/where"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我在哪里"
        android:background="#ff0000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/right_top"/>
</androidx.constraintlayout.widget.ConstraintLayout>

那么此时显示的样式,就是id为where的TextView相对于id为right_top的TextView的右边显示。如下图:


image.png

那么这个时候我们可以做一个简单总结:

app:layout_constraintBaseline_toBaselineOf

这个属性,是让A和B两个控件的基准线在同一个水平位置上,比如两个TextView,大小不同,字体的大小也不同,那么想要让这样两个不同大小不同字体大小的文本内容显示在同一个基线,则可以使用该属性。app:layout_constraintBaseline_toBaselineOf

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/right_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_1"
        android:gravity="center"
        android:text="右上角"
        android:textSize="32sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:id="@+id/where"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我在哪里"
        android:background="#ff0000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBaseline_toBaselineOf="@+id/right_top"
        app:layout_constraintRight_toLeftOf="@+id/right_top"/>
</androidx.constraintlayout.widget.ConstraintLayout>
image.png

二、约束布局的margin控制

在约束布局中,margin控制需要存在约束关系的才会生效,比如控件A某条边相对于控件B的某条边存在约束关系,则控件A与B之间的margin才会生效。

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/right_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_1"
        android:gravity="center"
        android:text="右上角"
        app:layout_goneMarginStart="20dp"
        android:layout_marginStart="20dp"
        android:textSize="32sp"
        android:visibility="gone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:id="@+id/where"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我在哪里"
        app:layout_goneMarginEnd="20dp"
        android:layout_marginEnd="20dp"
        android:background="#ff0000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/right_top"/>
</androidx.constraintlayout.widget.ConstraintLayout>

这里使用了两种margin属性,一种就是app:layout_goneMarginEnd,这个只在right_top被gone的时候生效;一种就是android:layout_marginEnd,任何时候都生效。
但是这里的margin需要生效,只有id为where的TextView被id为right_top的TextView所约束,那么id为where的TextView的margin相对于id为right_top的TextView的才生效。而id为right_top的TextView并没有被id为where的TextView约束,所以id为right_top的TextView的margin_start其实看不到生效。这里其实可以认为right_top的margin_start生效了,只不过是相对于parent的左边,但是因为right_top在parent的右上角,所以看不到这个margin效果

三、layout_constraintVertical_bias和layout_constraintHorizontal_bias

这两个属性单独使用并不能生效,水平方向的必须要给控件的左右两边都添加约束才会生效,垂直方向的必须要给控件的上下两边都添加约束才可以生效。

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button13"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintHorizontal_bias="0.4"
        app:layout_constraintVertical_bias="0"
        app:layout_constraintLeft_toRightOf="@+id/left_top"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteX="120dp"
        tools:layout_editor_absoluteY="189dp" />

    <TextView
        android:id="@+id/left_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_3"
        android:gravity="center"
        android:text="左上角"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="@id/root"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

比如这个例子,Button的左边被TextView的右边约束,Button的右边被parent约束,这样Button的左右两边都有约束,那么给Button添加水平方向的bias属性就可以生效,即根据Button的左边约束偏移一定的比例,这里就是相对于TextView的右边位置偏移40%。
bias的偏移,是根据控件的水平或者垂直方向的剩余位置的百分比来偏移。

四、ConstraintLayout中设置控件居中

如果是在ConstraintLayout中居中,则:

        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

如果是在两个控件的中间,则可以:

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/left_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_3"
        android:gravity="center"
        android:text="左上角"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="@id/root"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:id="@+id/right_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_1"
        android:gravity="center"
        android:text="右上角"
        app:layout_goneMarginStart="20dp"
        android:layout_marginStart="20dp"
        android:textSize="32sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我在哪里"
        android:background="#ff0000"
        app:layout_constraintLeft_toRightOf="@+id/left_top"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/right_top"/>
</androidx.constraintlayout.widget.ConstraintLayout>
image.png

五、设置宽高百分比

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="测试百分比"
        android:background="#ff0000"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintHeight_percent="0.3"
        app:layout_constraintWidth_percent="0.3"/>
</androidx.constraintlayout.widget.ConstraintLayout>

设置宽高百分比,首先设置app:layout_constraintHeight_default="percent"采用百分比形式,其次使用app:layout_constraintHeight_percent="0.3"设置一个0-1的百分比值,最后控件的宽高需要设置为0dp,只有宽高是设置为0dp的,百分比才生效。

六、在约束布局设置宽高为0dp的作用

在约束布局中,给控件的左右两边或者上下两边添加约束之后,给控件的宽高设置为0dp的时候,可以占满两个约束控件中间所有剩余空间。

<android.support.constraint.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_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/title"
        android:textSize="@dimen/sp_16"
        android:layout_marginStart="@dimen/dp_16"
        android:layout_marginTop="@dimen/dp_16"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <EditText
        android:id="@+id/et_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@null"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:hint="@string/compulsory"
        android:textSize="@dimen/sp_16"
        app:layout_constraintLeft_toRightOf="@+id/tv_title"
        android:layout_marginTop="@dimen/dp_16"
        android:layout_marginEnd="@dimen/dp_16"/>
</android.support.constraint.ConstraintLayout>

比如这个布局,我们需要EditText在TextView的右边,如果不给EditText设置0dp的宽度,而是设置了match_parent的话,则会占满屏幕宽度,没办法实现EditText在TextView的右边

七、max和min

在ConstraintLayout中给控件设置min的宽度和高度,必须是要控件的layout_width或者layout_height为wrap_content或者0dp时。给控件设置max的宽度或者高度的时候,必须是要控件的layout_width或者layout_height为0dp时。
不过在设置max的时候需要注意一点,如果单纯只是设置了0dp,如果没给控件添加对应的左右约束或者上下约束,比如没有设置左右约束,那么layout_constraintWidth_max设置的再大也不会超过整个控件的wrap_content的长度。


image.png

这里的绿色区域的控件,宽度显示的明显没有达到550dp,但是也不会继续变长了。
如果是设置了左右约束,那么最大宽度的限制也就是左右两个约束中间的剩余空间宽度


image.png

八、Guideline和Barrier

1.Guideline

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

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline1"
        android:layout_width="1000dp"
        android:layout_height="100dp"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="200dp"
        app:layout_constraintGuide_percent="0.04" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="10000dp"
        android:layout_height="10000dp"
        android:orientation="horizontal"
        app:layout_constraintGuide_end="300dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.2" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/color_10"
        android:gravity="center"
        android:text="测试位置"
        android:textSize="32sp"
        app:layout_constraintBottom_toTopOf="@+id/guideline3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="120dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

同时给Guide设置layout_constraintGuide_percent和layout_constraintGuide_begin的时候,layout_constraintGuide_begin并不会生效。
layout_constraintGuide_begin是给Guide设置相对于开始位置的偏移,layout_constraintGuide_end是给Guide设置相对于结束位置的偏移。
layout_constraintGuide_percent是设置Guide设置相对于起始位置的偏移百分比。
Guide的作用就是为了给控件的提供一个约束参考线,控件可以依靠这个线条约束。

2.Barrier

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:barrierDirection="end"
        app:constraint_referenced_ids="username1,password1" />

app:constraint_referenced_ids这里是添加约束的控件的id,app:barrierDirection是添加约束的位置,可以有end、start、left、right、top、bottom
添加不同的值,就可以让Barrier线条在约束的控件的对应位置上,比如end,就是让Barrier线条在username1和password1这两个控件的右边结束位置

3.Guideline和Barrier的区别

这两个都是线条,都是辅助约束的,但是这两个有一点区别,就是当控件比如出现切换手机语言,而造成控件上的文本显示长度出现变化的时候,Guideline并不会随着控件的长度变化而变化,这样就会造成约束不灵活,而Barrier可以根据控件的宽高变化,灵活移动位置。
所以控件宽高是随着内容动态变化的,建议使用Barrier,如果控件的内容是不变的,可以使用Guideline。

上一篇下一篇

猜你喜欢

热点阅读