Android ConstraintLayout 约束布局的使用介绍

ConstraintLayout,约束布局,兼容到Api9,可以通过托拉拽的方式来调整界面,也可以通过代码的方式(Android开发的肯定是习惯这种方式)。

在开发中,经常会有各种复杂的UI,然后,伴随着各种的嵌套,最后导致嵌套的层级太深,UI卡顿。ConstraintLayout无需任何嵌套,可以有效的减少嵌套的层级,达到UI性能优化的目的。

ConstraintLayout,作为一个新的控件,肯定会有很多的属性,方法需要我们了解。但是,它基本算是渐进式的,我们只要了解了基本的定位,就可以绘制界面了,然后,再深入的了解,相对来说,还是非常友好的。

你可以使用的约束类型:

  • 一、相对定位
  • 二、Margins
  • 三、居中定位与偏移
  • 四、圆形定位
  • 五、尺寸约束
  • 六、链(Chains)
  • 七、虚拟辅助对象
    • 7-1,Barrier
    • 7-2,Group
    • 7-3,Guideline
    • 7-4,Placeholder
  • 八、优化
  • 九、注意事项

一、相对定位

相对定位是在ConstraintLayout中创建布局的基本构建之一。只要我们了解了这些,我们就可以绘制一些简单的界面。

这些约束可以让你将给定的控件相对于另一个控件进行定位,有点类似于RelativeLayout。

你可以在横向和纵向上约束控件:

  • 横向:left,right,start,end等控制属性。
  • 纵向:top,bottom和text的baseline(基线对齐).

看下面的图
Android ConstraintLayout 约束布局的使用介绍_第1张图片

上面的图,
第一个图,标识出了view自身的top,bottom和text的baseline纵向的位置属性;
第二个图,标识出了left,right,start,end的横向位置属性,跟我们之前用的其他的布局一样,多了一个text的baseline对齐。

下面,我们看下可用的约束列表:

  • 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

我们看到约束列表的有很多属性。但是,主要就是left,right,top,bottom,baseline几个方向属性的控制。

我们可以把上面的所有属性都分为2个部分,看下图

Android ConstraintLayout 约束布局的使用介绍_第2张图片

上面,我们已经标注了2个部分的位置:

  • 第一部分,表示的就是,view自身的位置right,left,top,bottom
  • 第二部分,表示的就是,需要根据哪个view进行定位(这些toLeftOf…等等,其实跟RelativeLayout是一样的)

这里,我们举个例子,如下图,让View B在View A的右边。

在这里插入图片描述

这样,就是说,让view B自身的左边,在view A的右边。

我们知道第一个部分,表示的是自身。所以第一部分就是layout_constraintLeft。

第二部分表示的是根据哪个view来定位,在view A的右边(toRightOf,跟RelativeLayout一样)。

这样,我们就知道使用的是layout_constraintLeft_toRightOf.

这里,我们不仅可以根据另一个view定位,也可以根据ConstraintLayout(parent)来进行定位。

比如,左对齐父控件,就是自身的左边在父控件的左边。

这里有个要注意的地方,可能大家已经看到了,这些属性前面不再是android:,而是app:

到这里,我们的相对定位就说完啦,赶紧去试试吧。

二、Margins

我们知道,其他的控件,都有Margin属性,表示的就是2个控件的距离。

ConstraintLayout中,margin分为2种情况:

  • 2-1,在子view显示的时候(跟其他的布局一样)
  • 2-2,在子view隐藏的时候

2-1,子view显示的时候

这种情况,跟我们其他布局使用的时候是一样。我们先来看下margin的属性有哪些

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom

我们看到,这些属性跟其他的布局里面的一样,就是marginLeft,marginRight等等,这样,我们都已经用的很熟悉了,这里就不说了。

这里有个要注意的点:
如果,我们没有在相同方向上设置约束的话,我们设置的margin属性也不会有所用。

下面看个例子


    


上面,我们只设置了水平方向的约束,就是app:layout_constraintLeft_toLeftOf,layout_constraintRight_toRightOf。
但是,没有设置纵轴方向的约束(跟top,bottom相关的)。所以,上面的marginTop=10dp,其实是没有作用的。

下面看下正确的做法


    


我们使用layout_constraintTop_toTopOf,让textview的top跟parent的top对齐,就是顶部对齐,这样,再设置marginTop就可以起作用了。水平方向上是一个道理。

2-2,在子view隐藏的时候

这里,我们看下在view隐藏的时候,有哪些Margin属性。

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

我们可以看到这个跟普通的margin属性差不多,只不过,在前面加上了gone。

它表示的就是,如果view所依赖的另一个view隐藏后,自身的Margin属性。

举个例子,如下图
Android ConstraintLayout 约束布局的使用介绍_第3张图片

可以看到view B是通过view A来约束的。

 
    

这个时候,如果我们把view A设置了隐藏,那么view B就会移动到最左侧的距离(view A的Margin就不会计算了)。

如下图

Android ConstraintLayout 约束布局的使用介绍_第4张图片

当view A隐藏后,它身上的margin也就失效了。

这个时候,如果,我们想要view B距离左侧也有距离,并且,在view A显示的时候,它跟view A之间是没有距离的,这个时候,我们就用到了layout_goneMarginLeft的属性。

它表示,如果view A(约束的目标view)隐藏后,它的goneMarginLeft就会起作用;如果view A不隐藏,那么goneMarginLeft就不起作用。

下面,我们把view A隐藏,给view B添加这个属性


    

我们把A隐藏了,给view B添加了goneMarginLeft=20dp属性,再来看下效果图

在这里插入图片描述
是不是达到了我们想要的效果,再用不用在代码里面来写那些判断逻辑了。

Android ConstraintLayout 约束布局的使用介绍_第5张图片

到这里,ConstraintLayout的margin属性就说完了。主要是两点

  • 1,普通的margin,必须添加对应方向上的约束,margin属性才能起作用
  • 2,goneMargin属性,是在约束的目标view隐藏后,起作用的属性。

三、居中定位与偏移

  • 3-1,居中
  • 3-2,Bias,偏移百分比

3-1,居中

通过上面,我们基本上可以像RelativeLayout一样的来绘制一些简单的界面了,但是好像没办法把控件居中显示啊。

我们先看一下,下面的代码


    

这个view A,我们给他添加了(layout_constraintLeft_toLeftOf=“parent”)让view的左侧跟父view做的左侧对齐,(layout_constraintRight_toRightOf=“parent”)让view的右侧跟父view的右侧对齐

但是,view的大小是wrap_content的,并不能满足,我们的约束条件(两侧都不能到达,我们希望的位置上)。

在这种情况下,约束的作用就会将我们的view两侧平分,最终就是在父布局中居中显示,垂直居中跟这个是一个道理。

看下效果图

Android ConstraintLayout 约束布局的使用介绍_第6张图片

3-2,Bias,偏移百分比

使用上面的属性后,我们终于可以让view居中的显示了。但是,有时候,我们不希望view完全居中,比如,左右偏移一点?

这样,我们就需要通过Bias属性来调整view所在的位置,来达到我们想要的效果了。

  • layout_constraintHorizontal_bias :横向偏移
  • layout_constraintVertical_bias :垂直偏移

偏移的值范围是0-1之间,0表示最开始的位置(左侧或顶部),1表示结束的位置(右侧或底部)。

这个偏移的话,也是在对应方向上有约束并且是居中的约束才可以。

下面,我们给view A添加一个0.2的偏移


    


看下效果图

Android ConstraintLayout 约束布局的使用介绍_第7张图片

这里,我们看到view A已经偏移到左侧20%的位置上,达到效果了。

四、圆形定位

版本添加:1.1。

圆形定位就是说,你可以通过一个view的中心位置,在一定角度和距离上约束另一个view的中心位置。

我们先看下,属性有哪些:

  • layout_constraintCircle : 引用目标view的id
  • layout_constraintCircleRadius : 到目标view中心的距离
  • layout_constraintCircleAngle :角度 (范围, 0 到 360)

Android ConstraintLayout 约束布局的使用介绍_第8张图片
上图可以看到,view B的位置是根据view A的中心位置,半径radius及角度angle来确定的。

我们直接通过代码看下


	

在这里插入图片描述
这里可以看到,通过button A的中心,角度,和半径距离,我们确定了button B的位置。

五、尺寸约束

5-1,最大和最小的宽度,高度

你可以为ConstraintLayout约束布局定义最大和最小的尺寸大小。

  • android:minWidth 设置最小宽度
  • android:minHeight 设置最小高度
  • android:maxWidth 设置最大宽度
  • android:maxHeight 设置最大高度

当ConstraintLayout的大小设置为WRAP_CONTENT时,这些最大宽度和高度将被布局使用。

跟我们普通的布局是一样的。

5-2,view的大小约束

平通的view设置宽高(layout_width和layout_height),有3中方式,MATCH_PARENT,WRAP_CONTENT,指定具体的大小。

相较于普通的view,ConstraintLayout的子view也有3种不同的方式设置宽高(android:layout_width 和 android:layout_height)。

  • 指定具体的大小
  • 使用WRAP_CONENT
  • 使用0dp,相当于"MATCH_CONSTRAINT"

前两种方式跟其他的布局一样。关于MATCH_PARENT在ConstraintLayout里面,是不推荐使用。

我们可以使用,0dp(MATCH_CONSTRAINT)方式。然后,左右都跟parent的左右对齐就可以了。

我们用代码看下ConstaintLayout种,上面的几种情况




    

    

    

Android ConstraintLayout 约束布局的使用介绍_第9张图片
第一个,设置了wrap_content,跟其他的布局一样。
第二个,设置了0dp,发现会填充整个父控件的宽度。
第三个,设置0dp,并且有个marginLeft。

到这里,我们知道,出了0dp,其他的方式跟普通的布局是一样的。

如果,我们想实现match_parent的效果的话,我们只需要看第二个view,设置0dp,然后,跟父控件的左右侧对齐即可(app:layout_constraintLeft_toLeftOf="parent"和app:layout_constraintRight_toRightOf=“parent”)。

下面,我们看个特殊的情况。

5-3,WRAP_CONTENT : 强制约束

添加版本:1.1。

如果尺寸设置为WRAP_CONTENT,在1.1版本之前,约束不会限制生成的大小。但是在某些情况下,你可能希望使用WRAP_CONTENT,同时继续执行约束以限制生成的尺寸。

这种情况下,你可以添加对应的属性:

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

下面,我们举个例子



    

    


Android ConstraintLayout 约束布局的使用介绍_第10张图片

看效果,view A在布局右侧。view B位于view A的左侧并且在A和左侧屏幕的中间。我们看下代码实现。

看代码我们实现了效果,但是如果,我们的view B的内容过多时候,会是什么样呢?

Android ConstraintLayout 约束布局的使用介绍_第11张图片
不对啊,明明设置了B约束在A的左侧啊,为啥没有作用了呢?
我们发现view B上的约束,失效了。

这个时候,我们就需要强制约束宽度(layout_constrainedWidth),来保证B的位置,使我们的UI不变形了。



    

    


Android ConstraintLayout 约束布局的使用介绍_第12张图片
这里,我们看到,通过添加了layout_constrainedWidth=true后,我们的UI,终于跟我们想要的是一个效果了。

5-4,MATCH_CONSTRAINT (0dp)

添加版本:1.1。

MATCH_CONSTRAINT这种方式就是设置宽高为0dp。

当尺寸设置为MATCH_CONSTRAINT时,默认的行为就是让尺寸占据所有的可用空间。上面我们看过效果了。

再来看看还有哪些其他属性:

  • layout_constraintWidth_min and layout_constraintHeight_min :设置最小尺寸
  • layout_constraintWidth_max and layout_constraintHeight_max : 设置最大尺寸
  • layout_constraintWidth_percent and layout_constraintHeight_percent : 设置尺寸的百分比

下面我们就用百分比的属性,举个例子。

我们让子view占据父控件的一半的宽度
Android ConstraintLayout 约束布局的使用介绍_第13张图片
这里,可以看到,通过添加layout_ConstraintWidth_percent=0.5,我们的view的宽度就变成了父控件的一半。

5-5,百分比尺寸

要使用百分比尺寸。你需要设置一下内容:

  • 尺寸(width或height)设置成MATCH_CONSTRAINT(0dp)
  • app:layout_constraintWidth_default=“percent” or app:layout_constraintHeight_default="percent"的默认值,要设置成百分比
  • 设置layout_constraintWidth_percent or layout_constraintHeight_percent 的属性0到1之间

下面先看下效果
Android ConstraintLayout 约束布局的使用介绍_第14张图片
下面是代码
第一个,设置了layout_constraintWidth_default和layout_constraintWidth_percent,让控件是父控件的20%
第二个,设置了layout_constraintWidth_default属性是spread
第三个,设置了layout_constraintWidth_default属性是wrap




    

    

    


根据效果图,可以看出来layout_constraintWidth_default的属性设置

  • percent,结合layout_constraintWidth_percent属性,可以设置view的大小相对于父控件的百分比
  • spread,相当于 android:layout_width=“match_parent”
  • wrap,相当于android:layout_width=“wrap_content”

5-6,Ratio 宽高比

Ratio可以设置view的宽高比,为了让view可以限定宽高比,你最少需要把一个(layout_width或layout_height)设置为0dp(即,MATCH_CONSTRAINT)。

然后,使用layout_constraintDimensionRatio 属性。

   

这个将会把这个button的宽高比设置成1:1,即宽度=高度。
比率可以表示为:

  • 一个float类型的,表示宽度和高度的比率
  • "width:height"形式的比率

如果宽度和高度都设置成了MATCH_CONSTRAINT(0dp),也可以使用比率。在这种情况下,系统会设置满足所有约束下的最大尺寸,并保持宽高比。

如果要根据width来约束height,可以附加"W";如果根据height来约束width,可以附加"H";来分别约束宽度或高度。例如,width=0dp,则可以添加W用来约束宽度。H同理。

距离

    

这里,我们的宽高都设成了0dp。layout_constraintDimensionRatio设置的是"16:9"。

Android ConstraintLayout 约束布局的使用介绍_第15张图片
这个属性,对于,我们使用Banner轮播控件来说,是不是很有用处呢,再也不用在代码里面计算了。

六、链(Chains)

Chains 链在单个轴(水平或垂直)上提供了类似组的行为。在链的另一个轴上可以单独的进行约束。

6-1,创建链

如果一组控件通过双向的链接 连接在一起,则将其视为一个链。如下图

Android ConstraintLayout 约束布局的使用介绍_第16张图片

6-2,链头

链由在链上的第一个元素(链头)上设置的属性控制。

链头就是水平方向最左边的,垂直方向最上面的那个元素。

在这里插入图片描述

6-3,链中的Margins

如果在链接上指定了Margins,将会考虑这些margin。如果是扩展链,这些margins将会从分配的空间中去除。

6-4,链的样式

在链的第一个元素上设置属性layout_constraintHorizontal_chainStyle 或layout_constraintVertical_chainStyle时,链的行为将根据指定的样式更改(默认是CHAIN_SPREAD)。

下面看下链的样式:

  • CHAIN_SPREAD :元素将展开(默认样式)
  • Weighted chain :在 CHAIN_SPREAD 样式中, 如果有控件设置了MATCH_CONSTRAINT,它们将分了可用的空间。
  • CHAIN_SPREAD_INSIDE : 链的两端不会展开
  • CHAIN_PACKED :链的各个元素被包装到一起,子元素的水平或垂直偏移属性(bias)将影响压缩元素的位置
    Android ConstraintLayout 约束布局的使用介绍_第17张图片
    这面说了一堆,到现在,还没有开始写链啊。。。。。
    Android ConstraintLayout 约束布局的使用介绍_第18张图片

下面,我们就用CHAIN_SPREAD举个例子



    

在这里插入图片描述
这里,我们看到,给第一个view(链头)添加了layout_constraintHorizontal_chainStyle=spread这个属性,没有view都是相互约束的,这就是我们说的链。

(这里,第二个view添加了layout_constrainedWidth=true属性,不然的话,当它的内容过多时候,就会把其他两个view的位置全部占用了。有兴趣的可以试试)

6-5,链的weight

Chain链的默认样式是spread,让元素可以均匀的分布。跟上面的例子一样。

如果一个或多个元素的width或Height使用了0dp(MATCH_CONSTRAINT)的话,则它们会将剩余的空间给占用了。

如果,想让元素按照我们的想法来分配剩余的控件,那么,就需要用到属性layout_constraintHorizontal_weightlayout_constraintVertical_weight了,它会将剩余的空间,在这些使用约束控制的元素之间按照weight的值来分布(类似于LinearLayout的weight权重)。

例如,button A使用了weight=2,button B使用了weight=1,那么第一个元素占用的空间就是第二个的2倍。

看下代码



    

这个代码里button A 和button B把宽度都改成了0dp(MATCH_CONSTRAINT)。然后,给button A设置了weight=2,button B设置了weight=1。

所以,效果就是button A的宽度是button B的2倍。

Android ConstraintLayout 约束布局的使用介绍_第19张图片

6-6,margins和链

在Chain链中,使用margins时,margin是相互叠加的。

例如,在水平方向的Chain链中,如果一个view设置了10dp的右边距(marginRight),而它的下一个view设置一个5dp的左边距(marginLeft),则这两个view之间的距离是15dp。

我们添加margin属性看下



    

我们看上面的代码,给button A添加了marginRight=20dp,给button B添加了marginLeft=10dp。

所以,效果应该是中间有30dp。看下图
在这里插入图片描述

七、虚拟辅助对象

在ConstraintLayout中,除了上面介绍的功能外,还可以在ConstraintLayout中使用虚拟的辅助对象,来帮助我们进行布局。

  • Guideline。 允许我们创建水平和垂直的line,这些Guideline相对于ConstraintLayout来摆放
  • Barrier。可以把多个带约束的控件,当做一个整体
  • Group。可以控制多个控件的可见性
  • Placeholder。可以替换指定的控件。

7-1,Guideline

Guideline,ConstraintLayout的辅助对象。它不显示在设备上(标记为View.GONE),仅用来布局,并且只在约束布局中有效。

可以通过android:orientation设置水平(horizontal )还是垂直方向(vertical)。

它的属性有:

  • layout_constraintGuide_begin。距离父容器的起始位置(左侧或者顶部)的距离。
  • layout_constraintGuide_end。距离父容器的结束位置(右侧或底部)的距离。
  • layout_constraintGuide_percent。距离父容器的宽度或者高度的百分比。

下面,用代码演示下



    
    

我们让(layout_constraintGuide_percent=“0.2”),就是Guideline在父控件的20%宽度的位置。然后,让button A在Guideline的右侧对A进行横向定位。
Android ConstraintLayout 约束布局的使用介绍_第20张图片

7-2,Barrier

Barrier(屏障)可以引用多个控件,作为资源。并根据指定侧最极端的控件创建虚拟的准则。

例如,一个Barrier设置右侧(barrierDirection=right),它会将所有引入的控件添加一个右侧的屏障。其他的控件,就可以根据这个Barrier来设置自己的位置。

模拟场景:登陆界面

Android ConstraintLayout 约束布局的使用介绍_第21张图片

左侧的label字段,用户名,密码的长度明显不一样。但是,我们想让右侧的输入框位置都是对齐的。

这种情况下,我们就需要用到Barrier了。

我们把左侧的用户名,密码放到一个Barrier里面,然后,约束Barrier的右侧就可以了。然后,让输入框都根据Barrier来约束自己就可以了。

看下代码



    

    

    

    



我们看下效果图,

Android ConstraintLayout 约束布局的使用介绍_第22张图片

我们可以看到,最后的TextView是根据Barrier来约束的,已经摆放到这2个label按钮的后面。

Barrier这个控件,在使用的时候,好像在XML里面是看不到效果的,需要运行到设备上才可以。

最后,如果barrier引入了隐藏的(GONE)控件,则默认也会把隐藏的控件的解析位置上创建Barrier。如果不希望考虑隐藏的控件,可以通过把属性barrierAllowsGoneWidgets 设置为false(默认是true),来达到目的。

7-3,Group

Group是控制引用控件的可见性。把控件的id通过app:constraint_referenced_ids这个属性,引用到Group上。然后,就可以给这些控件统一的设置可见性了。

多个id引入通过","逗号隔开。


只需要把控件的id放到Group里面,就可以同时控制,显示/隐藏了。

这样,我们就能轻松的控制一组控件的显示/隐藏,而无需通过代码设置了。

最后,多个Group可以引用相同的控件,这种情况下,会根据Group在XML的声明顺序,来决定该控件的最终的可见性。

7-4,Placeholder

添加版本:1.1。

作用:当Placeholder上设置了另一个view的id,通过(setContent()),这个Placeholder就成为了有内容的view。如果该内容view存在屏幕上,则将其视为已离开其原始位置。

内容view是使用Placeholder的参数来进行定位的(跟其他view一样,该Placeholder也受布局约束)。

下面看下代码,现在界面上画一个button,如下



    

效果
Android ConstraintLayout 约束布局的使用介绍_第23张图片

我们看到,在屏幕的右上角,有个button在静静的呆着。。。。

下面,我们加入Placeholder。



    

通过content="@id/btn_placeholder"属性,我们把button的id设置给了Placeholder。Placeholder是水平和垂直都居中的。

效果如下
Android ConstraintLayout 约束布局的使用介绍_第24张图片

我们发现右上角的button,跑到了屏幕的中间,占用了Placeholder的位置,使用的是Placeholder的约束属性。

八、优化

在1.1中,公开了约束的优化。我们可以通过把属性app:layout_optimizationLevel添加到ConstraintLayout来优化。

属性的可选项有:

  • none。不优化
  • standard。默认的,仅优化直接约束和Barrier约束
  • direct。优化直接约束
  • barrier。优化Barrier(屏障)约束
  • chain。优化链约束
  • dimensions。优化尺寸约束。

最后,在2.0,还加入了Layer,自定义Helper,Flow等控件。

九、注意事项

9-1,Margin的使用

在相应的margin方向属性上,必须有约束。
比如,设置marginLeft,view必须在水平方向上有约束,否则,不起效果

9-2,wrap_content的使用

如果view使用的width或者height是wrap_content的问题,如果数据量过大,可能会早晨UI的错乱。
可以使用constraintWidth=true来限制。

9-3,特殊效果实现

之前,UI有个需求,如下图

Android ConstraintLayout 约束布局的使用介绍_第25张图片

需求:
标题显示:搜索内容,搜索的数量,还有一个图片Icon。

如果搜索标题太长的话,显示"…"。但是,搜索的数量跟Icon不能受影响。


下面,我们就通过ConstraintLayout来实现左边的内容,不考虑Icon。



    

    




实现思路:

1,先把2个view设置成链(Chain),然后设置链头(第一个view)的样式是"packed",让2个view连在一块(layout_constraintHorizontal_chainStyle=“packed”)。

2,设置bias偏移(layout_constraintHorizontal_bias=“0”),让它靠近父控件的左侧。

3,设置强制约束(layout_constrainedWidth=“true”),来限制第一个view的长度。

通过上面这些操作,我们就实现了,这个功能。

在这里插入图片描述
在这里插入图片描述

你可能感兴趣的:(Android,自定义控件,技术)