学习使用ConstraintLayout布局实战

一、概述

ConstraintLayout 布局已经出来有一两年了,最先开始因为视图化的布局,所以一直没有使用过,最近浏览其他博客的时候,多次看到ConstraintLayout 是官方推荐使用的布局,而且相对于其他的四大布局,有很多性能方面的优势。所以有必要学习和使用一下这个布局。下面开始吧!
引入依赖(已经到1.1版本了,是应该多尝试使用这个布局了)

implementation 'com.android.support.constraint:constraint-layout:1.1.0'

二、效果展示

不喜欢视图化布局,其实也可以手写属性来布局。下面展示下我看hongyang大神博客时手写布局的效果。
布局效果
下面是布局xml代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <ImageView
        android:id="@+id/img_banner"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="15dp"
        android:background="@color/colorPrimaryDark"
        app:layout_constraintDimensionRatio="H,16:9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <ImageView
        android:id="@+id/img_left"
        android:layout_width="146dp"
        android:layout_height="86dp"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="12dp"
        android:layout_marginTop="10dp"
        android:background="@color/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/img_banner" />

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="马云:一年交税170多亿马云:一年交税170多亿马云:一年交税170多亿"
        app:layout_constraintLeft_toRightOf="@+id/img_left"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@+id/img_left" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="8分钟前"
        app:layout_constraintBottom_toBottomOf="@+id/img_left"
        app:layout_constraintLeft_toLeftOf="@+id/txt_content" />

    <TextView
        android:layout_width="60dp"
        android:layout_height="60dp"

        android:background="@color/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHorizontal_bias="0.9"
        app:layout_constraintVertical_bias="0.9"/>
    <TextView
        android:id="@+id/tab1"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tab2" />

    <TextView
        android:id="@+id/tab2"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/holo_green_light"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toRightOf="@+id/tab1"
        app:layout_constraintRight_toLeftOf="@+id/tab3"
    />

    <TextView
        android:id="@+id/tab3"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/holo_red_light"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toRightOf="@+id/tab2"
        app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

三、属性介绍

结合这个上面这个布局介绍下ConstraintLayout的属性吧

1、相对位置(Relative positioning)

在横向和纵向上添加约束关系来固定控件位置,官方一共提供给我们这些相对约束属性:这里写图片描述
下面我们对比下效果
没有添加约束

<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="按钮01"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="按钮2"/>

</android.support.constraint.ConstraintLayout>

没有添加按钮2在按钮1的右边的约束

<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮01"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintLeft_toRightOf="@+id/btn_01"/>

</android.support.constraint.ConstraintLayout>

没有添加约束没有添加按钮2在按钮1的右边的约束
仅仅添加了一个app:layout_constraintLeft_toRightOf="@+id/btn_01"属性就可以达到了RelativeLayout布局的android:layout_toLeftOf="@id/btn_1"所要的效果。
相对位置的约束属性的格式基本是layout_constraintxxx_toxxxOf=id这种格式,理解起来其实并不难,constraintxxx代表当前控件的约束方向,如上图的效果constraintLeft就是就是btn_02按钮的左边约束。toxxxOf被约束的控件的方向,如上图id是btn_01 就代表与id为btn_01控件的右边方向约束在一起。app:layout_constraintLeft_toRightOf="@+id/btn_01"结合起来就是当前控件btn_01按钮的左边与id为btn_01的控件的右边相约束。 关于约束这个词的理解,你可以理解成用带弹性的绳子相连接起来。
下面在展示几个例子:
按钮01 在按钮02的正下方

<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="按钮01"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintLeft_toLeftOf="@+id/btn_01"
        app:layout_constraintTop_toBottomOf="@+id/btn_01"
        app:layout_constraintRight_toRightOf="@+id/btn_01"/>


</android.support.constraint.ConstraintLayout>

首先对按钮01 使用app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent" 使得按钮01的左边和顶部与父布局的左边和顶部约束,这样按钮就被固定在左上角。 然后对按钮02 使用app:layout_constraintLeft_toLeftOf="@+id/btn_01"将按钮02的左边与按钮01的左边相约束,然后使用app:layout_constraintTop_toBottomOf="@+id/btn_01" 让按钮02的顶部与按钮01的底部相约束,这样按钮02就在按钮01的正下方。最后使用 app:layout_constraintRight_toRightOf="@+id/btn_01" 让按钮02的右边与按钮01的右边相约束,保持永远对齐。

2、倾向(bias)

这里写图片描述
倾向分为两个方向 横向和纵向, 也就是说左右和上下两边出现受力不均,造成倾向,比如左边约束的力是右边约束的力之比是9:1

<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="80dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="按钮01"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintVertical_bias="0.3"
        app:layout_constraintHorizontal_bias="0.9"/>


</android.support.constraint.ConstraintLayout>

这里写图片描述
理解:左边的间距占左右边间距之和的90%,上间距占上下间距之和的30%

3、圆心定位

这是在1.1版本添加的新属性,貌似没有自动提示
这里写图片描述

<?xml version="1.0" encoding="utf-8"?>
<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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="80dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="按钮01"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintCircle="@+id/btn_01"
        app:layout_constraintCircleRadius="90dp"
        app:layout_constraintCircleAngle="20"/>


</android.support.constraint.ConstraintLayout>

这里写图片描述
圆心定位意思就是基于两个控件的中心,通过radius和angle来控制控件的位置。angle角度不支持负值。默认以被定位控件(btn_01)的Y轴正方向为零度。

4、可见性约束

隐藏前隐藏后
可以看到区别开始是按钮01左边约束父布局的左边,然后按钮02约束按钮01的右边。 但是当按钮01隐藏以后,按钮02直接约束到父布局的左边,事实上按钮根本没有约束父布局的左边。 这里小编的理解,就是之前的隐藏的控件的布局约束依然有效,只不过按钮01的所有边距变成了0.如果你有更好的理解请告诉我,谢谢。

5、控件尺寸约束

通常我们定义控件的长和宽,android:layout_width=""android:layout_height="" 来设置控件的大小。
ConstraintLayout布局设置方式:

  • 固定值
  • wrap_content
  • 0dp(相当于MATCH_CONSTRAINT)

那match_parent呢?看下面这段话

Important: MATCH_PARENT is not recommended for widgets contained in a ConstraintLayout. Similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to “parent”.

大概意思是不推荐使用match_parent在ConstraintLayout布局中设置大小,类似的功能可以使用约束设置左右或者上下指定约束到父布局上。
那怎样实现其他四大布局match_parent沾满父窗体剩下控件的效果呢? 可以使用0dp来代替
match_parent的效果

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="48dp"
        android:layout_marginTop="112dp"
        android:text="按钮01"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintLeft_toRightOf="@+id/btn_01"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

这里写图片描述
0dp实现的效果

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <Button
        android:id="@+id/btn_01"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="48dp"
        android:layout_marginTop="112dp"
        android:text="按钮01"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/btn_02"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="按钮2"
        app:layout_constraintLeft_toRightOf="@+id/btn_01"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

这里写图片描述

6、比例(Ratio)

app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintDimensionRatio="W,16:9"

这里的比例指的是占父布局的高度和宽度的比例

7、链条(Chains)

链条适合于横向或者纵向一排的控件的布局方式。
首先要创建一个链条,就是一排控件首位相互约束,如下图
这里写图片描述
这里写图片描述
类似的效果的代码像这样,创建了一个链条

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">
    <TextView
        android:id="@+id/tab1"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tab2" />

    <TextView
        android:id="@+id/tab2"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/holo_green_light"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/tab1"
        app:layout_constraintRight_toLeftOf="@+id/tab3"
    />

    <TextView
        android:id="@+id/tab3"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="@android:color/holo_red_light"
        android:gravity="center"
        android:text="tab1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/tab2"
        app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

效果就像这样
这里写图片描述
看似效果跟LinearLayout的比重布局很相似,但是它有和LinearLayout不一样的效果,就是给链条添加样式。
这里写图片描述

  • CHAIN_SPREAD 元素被分散开(默认样式)
  • 在CHAIN_SPREAD模式下,如果一些控件被设置为MATCH_CONSTRAINT,那么控件将会把所有剩余的空间均分后“吃掉”
  • CHAIN_SPREAD_INSIDE Chain两边的元素贴着父容器,其他元素在剩余的空间中采用CHAIN_SPREAD模式
  • CHAIN_PACKED Chain中的所有控件合并在一起后在剩余的空间中居中

四、总结

看完了关于ConstraintLayout布局属性的介绍,是不是感觉非常强大,不仅有丰富的相对位置约束,还有比例、倾向的设置,具备RelativeLayoutLinearLayout两个最常用布局的各种优点。关键在性能上也有优势,我们还有什么理由不尝试呢?
参考链接:
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout
https://blog.csdn.net/lmj623565791/article/details/78011599

猜你喜欢

转载自blog.csdn.net/dingshuhong_/article/details/80195498
今日推荐