无比强大的ViewGroup——ConstraintLayout

ConstraintLayout是一种可以灵活的控制view大小和权重的view容器。

支持Android Api 9以上

目前它有以下的约束方式:

  1. Relative positioning相对位置约束
  2. Margins间距约束
  3. Centering positioning 中心约束
  4. Circular positioning 圆形约束
  5. Dimension constraints 尺寸约束
  6. Chains 链式约束
  7. Virtual Helpers objects 虚拟帮助对象
  8. Optimizer 优化

Relative positioning

相对位置约束是指布局中view相对于其它view的位置来设置自己的位置。分为纵向和横向两种:

  • 横向: left, right, start, end

一般情况下,View开始部分就是左边,但是有的语言目前为止还是按照从右往左的顺序来书写的,例如阿拉伯语,在Android 4.2系统之后,Google在Android中引入了RTL布局,更好了支持了由右到左文字布局的显示,为了更好的兼容RTL布局,google推荐使用MarginStart和MarginEnd来替代MarginLeft和MarginRight,这样应用可以在正常的屏幕和由右到左显示文字的屏幕上都保持一致的用户体验。

  • 纵向:top, bottom, text baseline

下面举个示例:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <include 
        layout="@layout/view_title_bar"
        android:id="@+id/view_title"/>
    <TextView
        android:id="@+id/tv_one"
        android:text="ViewA"
        ······
        app:layout_constraintTop_toBottomOf="@id/view_title"
        ······
        />
    <TextView
        android:text="ViewB"
        ······
        app:layout_constraintTop_toBottomOf="@id/tv_one"
        ······
        />
</android.support.constraint.ConstraintLayout>

得到的效果如下图:

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

Margins

同其它ViewGroup一样,它也有Margins约束条件,不同的是当参照控件可见性为GONE的时候又多了一些其它的属性。举个例子,当A控件 约束 在B控件的左边,B控件GONE了,此时A会额外拥有一个margin的能力,来“补充”B消失的导致的“位移”。

ViewB GONE 之前
ViewB GONE 之后

下面是代码实现:

<TextView
        ······
        android:id="@+id/tv_B"
        android:layout_width="100dp"
        android:text="ViewB"
        app:layout_constraintLeft_toRightOf="parent"
        android:visibility="visible"
        />
        
 <TextView
        ······
        android:id="@+id/tv_D"
        android:text="ViewD"
        app:layout_goneMarginLeft="120dp"
        android:layout_marginLeft="20dp"
        app:layout_constraintLeft_toRightOf="@id/tv_B"
       />

下面罗列一下它的约束条件:

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom
  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

Centering positioning and bias

我们如何使控件居中呢?

这里我们先来看看如何让控件在容器中水平居中。

<TextView
        android:id="@+id/tv_A"
        ······
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        ······ />

是就是这么奇妙,这样控件就在容器中水平居中了,垂直居中同理。那么如果是两个控件中间且居中呢?

直接上代码:

<TextView
        android:id="@+id/tv_B"
        android:text="ViewB"
        ······/>

    <TextView
        android:id="@+id/tv_C"
        android:text="ViewC"
        ······
        app:layout_constraintRight_toLeftOf="parent"
         />
    <TextView
        android:id="@+id/tv_D"
        android:text="ViewD"
        ······
        app:layout_constraintLeft_toLeftOf="@id/tv_B"
        app:layout_constraintRiht_toRightOf="@id/tv_C"
         />

只要使得ViewD分别于ViewB和ViewC产生依赖,只要就居中了。

控件就某一方向不居中的情况

比如使得ViewA距左边30%而不是50%

<TextView
        android:id="@+id/tv_A"
        ······
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        ······ />

当屏幕的尺寸变化时,这种方式能很好的兼容。

Circular positioning (Added in 1.1)

在1.1版本中添加了,圆形约束条件。下面是其相关的属性:

  • layout_constraintCircle : 参照widget的id
  • layout_constraintCircleRadius : 中心点距离参照widget中心的距离
  • layout_constraintCircleAngle : 角度,取值范围[0,360]
ConstraintLayout

那么来看下下图中的效果是如何实现的。

ConstraintLayout
<Button android:id="@+id/buttonA" ... />
  <Button android:id="@+id/buttonB" ...
      app:layout_constraintCircle="@+id/buttonA"
      app:layout_constraintCircleRadius="100dp"
      app:layout_constraintCircleAngle="45" />

Visibility behavior

可见性约束,GONE通常来讲是不会展示在页面上的,但是在ConstraintLayout中:

  1. 相当与将控件的大小缩小成为一个点,它的宽和高约等于0
  2. 它与其它控件的依赖关系是依然存在的,但是自身的margin是几乎等于0的

Dimensions constraints

尺寸约束,同其它ViewGroup一样对控件的宽和高给出最大值和最小值。对应的属性值如下:

  • android:minWidth
  • android:minHeight
  • android:maxWidth
  • android:maxHeight

上面的属性,在控件申明为wrap_content有效

Widgets dimension constraints

控件可以通过android:layout_widthandroid:layout_height设置自己的大小,这两个属性的值三种情况:

  1. 使用具体确定的数值,或者是资源xml中定义的具体尺寸.
  2. 使用WRAP_CONTENT,会自行计算大小
  3. 使用0dp, 其效果等同于MATCH_CONSTRAINT

需要注意的是: MATCH_PARENT在ConstraintLayout不推荐使用。可以将控件的left/righttop/bottom约束于parent。

WRAP_CONTENT(1.1)

在ConstraintLayout中,仍然可以对WRAP_CONTENT的最大尺寸进行约束:

  • app:layout_constrainedWidth=”true|false”

app:layout_constrainedHeight=”true|false”
当其中一个被设置为true时,控件的最大宽高任然可以被约束链约束,需要注意的是,这样做会使布局变慢一些。

MATCH_CONSTRAINT(1.1)

当宽高被设为MATCH_CONSTRAINT,这个控件将尝试占据布局上所有可用的地方,但同时会被这些属性所限制:

  • layout_constraintWidth_min/layout_constraintHeight_min:最小宽高

layout_constraintWidth_max/layout_constraintHeight_max:最大宽高

layout_constraintWidth_percent/layout_constraintHeight_percent:宽高相对于父容器的百分比。

注意:这些属性同时可以设置为wrap;
当使用百分比尺寸的时候,应当设置宽高为MATCH_CONSTRAINT;
父容器需要设置app:layout_constraintWidth_default=”percent”或app:layout_constraintHeight_default=”percent”(在1.1-beta2以后不再必须设置)

设置比例

constraintLayout支持子控件设置其宽高比,要使该特性生效至少需要将宽高中的一个设置为0dp(MATCH_CONSTRAINT)

<Button 
    ······
    android:layout_width="wrap_content"
                   android:layout_height="0dp"
                   app:layout_constraintDimensionRatio="1:1" />

宽和高之比可以用下面两种方式:

  1. 一个float数值,其等于宽/高的值
  2. 使用比例,例如:“2:1”

注意:当宽高均被设为0dp时,父容器将尝试在满足所有约束条件及比例的同时,占据最大的宽高;
如果只想对某个方向设置比例,则可以在属性前面加上W或H,与比例以,隔开:

<Button android:layout_width="0dp"
                   android:layout_height="0dp"
                   app:layout_constraintDimensionRatio="H,16:9"
                   app:layout_constraintBottom_toBottomOf="parent"
                   app:layout_constraintTop_toTopOf="parent"/>

Chains

链使我们能够对一组在水平或竖直方向互相关联的控件的属性进行统一管理。成为链的条件是:一组控件他们通过一个双向的约束关系链接起来

ConstraintLayout.jpg

注意:链的属性是由一条链的头结点控制的。而头结点的定义是一条链中位于最左端的控件。

ConstraintLayout

链的Margins

ConstraintLayout支持对链添加Margin,如果这条链的控件是分散分布的,将会从已分配给链的空间中减去设置的链边距。

链的Style

链支持设置他们的Style,只需在头结点指定layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle。共支持五种类型:

  • CHAIN_SPREAD(默认值):链中的元素将分散分布;

  • Weighted chain:在CHAIN_SPREAD模式中,如果某些组件被设置成MATCH_CONSTRAINT,他们将会占据所有空余空间并分散分布;

  • CHAIN_SPREAD_INSIDE:类似于CHAIN_SPREAD,但链的两端不会分散;

  • CHAIN_PACKED:链中的元素将会紧密相连在一起,偏移(bias)的设定将会影响他们在容器中所处的位置

  • Weighted chains:当链处在默认的模式(CHAIN_SPREAD)且其中一个或多个元素被设置为MATCH_CONSTRAINT时,他们将平均占据剩下的空余空间;如果其中的结点同时设置了

  • layout_constraintHorizontal_weight或layout_constraintVertical_weight属性,那么他们将根据所设置的比重来分配剩下的空间。

ConstraintLayout

Virtual Helper objects

虚拟辅助类部件它们最终不会在界面上呈现出来,但可以帮助我们更好更精细地控制布局。目前。所支持的这类部件包括:

1. Guideline

Guideline可以放在竖直方向或水平方向,水平Guideline的高为0,宽度与父容器一致;竖直Guideline同理。
Guideline 具有三类特殊的属性:

  • layout_constraintGuide_begin:设置Guideline 距离父容器起始位置的距离(left或top);

  • layout_constraintGuide_end:设置Guideline 距离父容器尾部的距离(right或bottom);

  • layout_constraintGuide_percent:设置Guideline 相对于父容器宽度/高度的百分比位置。

2. Barrier(1.1)

Barrier 使用多个控件作为参考,在这些控件中,选取在特定方向最边缘的的控件创建一条Guideline。
constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。

3. Group(1.1)

Group 用于控制所引用的一组控件的可见性(Visibility),constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。

<android.support.constraint.Group
              android:id="@+id/group"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:visibility="visible"
              app:constraint_referenced_ids="button4,button9" />

注意:多个Group 部件可以引用相同的控件,这时Group 在xml中的定义顺序将决定这个控件最终的可见性。

Optimizer(1.1)

在1.1 版本中放出了ConstraintLayout的优化模式。可以通过设置app:layout_optimizationLevel的优化等级,有以下值:

  • none : 无优化
  • standard : 默认优化. 只优化direct和barrier
  • direct :
  • barrier :
  • chain : 优化链式
  • dimensions : 优化尺寸测量 (experimental), 减少测量度量

以上优化的属性默认是关闭的,可以同时开启多个如:app:layout_optimizationLevel="direct|barrier|chain"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容