继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

ConstraintLayout用法详解

klivitamJ
关注TA
已关注
手记 42
粉丝 74
获赞 570

前几天,我刚写了一篇批判社会的文章。如今滴滴司机的事件让全国知道这件事儿的人聚拢了起来。其实生活在这种环境下,我们会不得不像生活妥协。用《我不是药神》的一句话就是:“我相信未来一定会更好”。

未来一定会更好的

说在前头

以前在写布局的时候,经常会写出这样的布局:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical">



    <RelativeLayout

        android:layout_width="wrap_content"

        android:layout_height="wrap_content">



        <LinearLayout

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:orientation="horizontal">



            <TextView

                android:layout_width="wrap_content"

                android:layout_height="wrap_content" />



            <TextView

                android:layout_width="wrap_content"

                android:layout_height="wrap_content" />w

        </LinearLayout>

    </RelativeLayout>



</LinearLayout>

这种代码本身写法是没有错误的,也能完成业务需求。但是一旦页面复杂起来,这种嵌套很容易造成页面的卡顿。因为查看源码得知,视图的渲染是一层一层渲染的,这种复杂度很高的渲染将会比简单的布局渲染的时间会加长。

在16年I/O大会上,google发布了全新的布局–ConstraintLayout。根据官方的解释,这个布局主要有下面三个优点:

  • 可以减轻复杂度,让页面性能更好。(性能优势

  • 更加友好的适配

  • 入手友好

一、 ConstraintLayout基本属性介绍:

1、 基本属性

谈到ConstraintLayout,就要从最基本的几个属性来谈谈:

  • 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

关于这些属性的名字呢!我就不一一赘述了,大家敲一下代码就晓得了。我就抛砖引玉的先做一个示例吧:

如图:要达成这样的布局,如果按照以前的写法的话,估计需要嵌套个两层,我这里就不多加赘述了,有兴趣的可以自己去写一写。但是用上ConstraintLayout,代码如下:


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



    <ImageView

        android:id="@+id/item_text_img"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:background="@mipmap/ic_launcher"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent" />



    <TextView

        android:id="@+id/item_text_title"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/item_text_title_defalt"

        android:textSize="20sp"

        android:textStyle="bold"

        app:layout_constraintStart_toEndOf="@id/item_text_img"

        app:layout_constraintTop_toTopOf="@id/item_text_img" />



    <TextView

        android:id="@+id/item_text_content"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/item_text_content_defalt"

        android:textSize="16sp"

        app:layout_constraintStart_toStartOf="@id/item_text_title"

        app:layout_constraintTop_toBottomOf="@id/item_text_title" />



</android.support.constraint.ConstraintLayout>

上面的代码,我们可以发现一个布局就可以解决问题。layout_constraint可以依靠于一个基准的id或者是parent来定位。

2、 margin

那张图会比较拥挤,我想带来一个间距,达到这样的效果:

这样就需要用到margin了,代码如下:


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



    <ImageView

        android:id="@+id/item_text_img"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:background="@mipmap/ic_launcher"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent" />



    <TextView

        android:id="@+id/item_text_title"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/item_text_title_defalt"

        android:textSize="20sp"

        android:layout_marginStart="10dp"

        android:textStyle="bold"

        app:layout_constraintStart_toEndOf="@id/item_text_img"

        app:layout_constraintTop_toTopOf="@id/item_text_img" />



    <TextView

        android:id="@+id/item_text_content"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/item_text_content_defalt"

        android:layout_marginTop="5dp"

        android:textSize="16sp"

        app:layout_constraintStart_toStartOf="@id/item_text_title"

        app:layout_constraintTop_toBottomOf="@id/item_text_title" />



</android.support.constraint.ConstraintLayout>

首先我们值得注意的是:

item_text_img 使用 layout_marginEnd是无效的,不信读者可以试试。并且在使用layout_margin*的时候,一定要确定对应方向的位置,不然也是无效的。

3、 关于view gone

现在有这么一个样式的布局:

代码如下:


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



    <Button

        android:id="@+id/frist_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:background="#ffff0000"

        android:text="frist"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent" />



    <Button

        android:id="@+id/second_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginStart="10dp"

        android:layout_marginTop="10dp"

        android:background="#ffff0000"

        android:text="second"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toEndOf="@id/frist_btn"

        app:layout_constraintTop_toBottomOf="@id/frist_btn" />



    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginStart="10dp"

        android:layout_marginTop="10dp"

        android:background="#ffff0000"

        android:text="final"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toEndOf="@id/second_btn"

        app:layout_constraintTop_toBottomOf="@id/second_btn" />



</android.support.constraint.ConstraintLayout>

如果中间的second的visible为Gone或者是invisible会成如何呢?

View为gone的示例图

view为invisible的示例图

当second为gone了之后,我们发现final就会直接继承second的位置关系占领住second的位置。但是当second为invisible了则保留second的位置。所以尽量使用invisible。当然google还是提供了一种方法:layout_goneMargin,在一定程度上可以解决这个问题,有兴趣的可以试试这个属性。

4、 居中

关于居中对齐这个事儿了,无论是在写前端和Android端都是一个必须知道的东西,如果了解透了,其实并没有什么的花里胡哨的东西。看下面一段代码:


<?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="100dp"

    android:background="@android:color/darker_gray">



    <Button

        android:id="@+id/frist_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:background="#ffff0000"

        android:text="frist"

        android:textColor="@android:color/white"

        app:layout_constraintTop_toTopOf="parent"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintEnd_toEndOf="parent"

        />

</android.support.constraint.ConstraintLayout>

效果如下:

但是google官方还给予了一个bias属性,如下所示:


app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintHorizontal_bias="0.3"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toTopOf="parent"

app:layout_constraintVertical_bias="0.8" 

得到的效果图如下:

如上图可知道,当位置都确定的情况下bias可以设置权重

由上面的示意图可以知道,当我们确定button的宽度和高度非0之后,再与parent的四周对齐之后。控件会与parent的四周构成一个弹簧,从而将控件拉到居中的位置,为什么说确定控件的宽度和高度呢?来看下面一段代码:


   android:layout_width="0dp"

   android:layout_height="0dp"

效果图如下:

image.png

这里我们会发现控件被拉成和父布局一样的大小。

5、 ratio

layout_constraintDimensionRatio:即宽和高成一定的比例,其值可以是"width:height"的形式,也可以是width/height的值。该属性生效的前提:宽和高其中有一项为0,有constraint。代码如下:


android:layout_width="0dp"

android:layout_height="20dp"

app:layout_constraintDimensionRatio="4"

效果图如下:

由上图可以知道:若有一项为0dp,另一项不为0时。则该项值按照比例计算出来。比如高为20dp,宽为0dp,radio为"4",则最终宽为80dp


android:layout_width="0dp"

android:layout_height="0dp"

app:layout_constraintDimensionRatio="4"

效果图如下:

image.png

如果两项都为0dp,则尺寸会设置为满足约束的最大值并保持比例。相当于该属性失效。

二、 GuideLine基准线介绍:

这个很简单的,看英文名称大概就能猜出来,这个东西就是一个辅助线的意思。众所周知,contractlayout是根据四周的环境分布来确定位置的,有了这个东西就能有很大的裨益。先来看一下它有哪些方法:

  • orientation:基准线的方向

  • layout_constraintGuide_begin:距离父布局的左边或者上边多大距离

  • layout_constraintGuide_end:距离父布局的右边或者下边多大距离

  • layout_constraintGuide_percent:百分比,0~1,距离父布局的左边或者上边占父布局的比例

实例代码如下:


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

    android:background="@android:color/darker_gray">

    

    <android.support.constraint.Guideline

        android:id="@+id/test_guide_line"

        android:layout_width="match_parent"

        android:layout_height="wrap_content" 

        android:orientation="horizontal"

        app:layout_constraintGuide_begin="200dp"/>



    <Button

        android:id="@+id/frist_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="test"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toBottomOf="@id/test_guide_line" />



</android.support.constraint.ConstraintLayout>

效果图如下:

这个属性比较简单,其他的我就不多加赘述了。

三、 Group

有的时候,因为页面的需要经常会需要控制多个view的显示和隐藏,所以官方在contractlayout1.1增加了 Group属性,用来控制多个view的显隐性。


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

    android:background="@android:color/darker_gray">

    <android.support.constraint.Group

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:visibility="invisible"

        app:constraint_referenced_ids="left_btn,right_bot_btn"/>

    

    <android.support.constraint.Group

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" 

        android:visibility="visible"

        app:constraint_referenced_ids="right_btn,left_bot_btn"/>



    <Button

        android:id="@+id/left_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="left"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent"/>

    

    <Button

        android:id="@+id/right_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="right"

        android:textColor="@android:color/white"

        app:layout_constraintEnd_toEndOf="parent"

        app:layout_constraintTop_toTopOf="parent"/>

    <Button

        android:id="@+id/left_bot_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="left"

        android:textColor="@android:color/white"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintStart_toStartOf="parent"/>



    <Button

        android:id="@+id/right_bot_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="right"

        android:textColor="@android:color/white"

        app:layout_constraintEnd_toEndOf="parent"

        app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

这里要值得注意的是:

  • xml中,可见性配置的优先级:Group优先于View,下层Group优先于上层。

  • Group只能映射同级layout下的ConstraintLayout下的View,其他级别下的View没有效果。

  • constraint_referenced_ids里直接写的是id的字符串,初始化后会通过getIdentifier来反射查找叫该名字的id。所以如果你的项目用了类似AndResGuard的混淆id名字的功能,切记不要混淆app:constraint_referenced_ids里的id,否则在release版本就会因找不到该id而失效。或者也可以通过代码setReferencedIds来设置id(这个是看的别人的😂😂😂)。

四、 Placeholder

这个叫做占位属性,也是我在看别人的文章里面看到的。先看代码:


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

    android:background="@android:color/darker_gray">



    <Button

        android:id="@+id/place_holder_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="right"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintEnd_toEndOf="parent"/>



    <Button

        android:id="@+id/left_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="left"

        android:textColor="@android:color/white"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent" />



    <Button

        android:id="@+id/right_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="right"

        android:textColor="@android:color/white"

        app:layout_constraintEnd_toEndOf="parent"

        app:layout_constraintTop_toTopOf="parent" />



    <Button

        android:id="@+id/left_bot_btn"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="left"

        android:textColor="@android:color/white"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintStart_toStartOf="parent" />



    <android.support.constraint.Placeholder

        android:id="@+id/place_holder"

        android:layout_width="wrap_content"

        android:layout_height="50dp"

        android:background="#ffff0000"

        android:text="right"

        app:content="@+id/place_holder_btn"

        android:textColor="@android:color/white"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintEnd_toEndOf="parent" />





</android.support.constraint.ConstraintLayout>

效果图如下:

这个布局存在的效果就是占位符,当content指向另外一个组件的时候,组件本身会gone掉,然后装载到placeholder的位置。(我还没摸透这个存在的意义)

五、 Barrier

关于这个属性,直接来看代码比较好理解一点:


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

    android:background="@android:color/darker_gray">



    <Button

        android:id="@+id/frist_btn"

        android:layout_width="20dp"

        android:layout_height="50dp"

        android:layout_marginTop="20dp"

        android:background="#ffff0000"

        android:textColor="@android:color/white"

        app:layout_constraintTop_toTopOf="parent"

        app:layout_constraintStart_toStartOf="parent" />





    <Button

        android:id="@+id/second_btn"

        android:layout_width="20dp"

        android:layout_height="50dp"

        android:layout_marginStart="40dp"

        android:layout_marginTop="40dp"

        android:background="#76ea0a"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent" />

    

    <android.support.constraint.Barrier

        android:id="@+id/barrier"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        app:barrierDirection="top"

        app:constraint_referenced_ids="frist_btn,second_btn"/>



    <Button

        android:id="@+id/final_btn"

        android:layout_width="20dp"

        android:layout_height="50dp"

        android:background="#0a24ea"

        android:layout_marginStart="100dp"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="@+id/barrier"

        />





</android.support.constraint.ConstraintLayout>

效果图如下:

我想由上面的代码,应该晓得了Barrier的作用。我的理解就是这是一个虚拟的view,跟guideline一样辅助view定位的。

但是当红色的布局gone的时候回发生什么呢?

这里呢?我也是看一篇文章里面这么说的,此时需要添加这么个属性:


app:barrierAllowsGoneWidgets="false"

效果图如下:

就不用管第一个view的显隐性了,直接去对齐第二个选项了。

当然Barrier这个是我看别人写的文档看来的,暂时还没有在项目中使用,后续会在里面多多使用这些新的特性的。

说在最后

首先说一下为什么要写这篇文章,第一是:大学同学在问我Android相关的知识;第二是:自己也想在接下来的时间里面多总结一点Android方面的知识。毕竟做Android这么久了。也不是说转前端就不管了。无论怎么说 还是希望Android和前端两匹马拉着我向大佬层次迈进的。

不知不觉我从开始写文章以来已经过去了6个月了,其实相对于以前能力并没有显著的提高。并且还花费着我很多的时间(运行、总结的时间),但是我还是一如既往的坚持了下来。我期待着厚积薄发、期待着傻人有傻福的一天😂😂😂

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP