ConstraintLayout 1.1版本的新特性

转自:
ConstraintLayout 1.1版本的新特性

约束布局ConstraintLayout看这一篇就够了


ConstraintLayout被译为约束布局,推出它旨在避免传统布局绘制界面时,可能会带来的overdraw等问题,在1.1.x版本,较之1.0.x版本推出了一些新功能(之前的介绍,见此篇:ConstraintLayout使用).

本篇使用的Constraint-layout版本如下:

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

1: Circular Position(极坐标定位)

此功能允许元素之间以: 圆心 + 距离 + 角度的方式进行相对定位
更云山雾罩的说是: 以前的定位方式都是基于平面直角坐标系,上下左右+距离定位的,现在允许以极坐标的方式进行定位了
共有3个相关属性:

  • layout_constraintCircle:作为约束中心的控件id
  • layout_constraintCircleAngle:被约束控件距圆心的的距离,即圆的半径
  • layout_constraintCircleRadius:被约束控件 与 圆心 及 向上(statusBar方向)的夹角

举个栗子:

<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"
    tools:context=".MainActivity">


    <!--
layout_constraintCircle 约束的控件的id
layout_constraintCircleRadius 约束距离圆心的距离,也就是圆的半径
layout_constraintCircleAngle 约束的角度(0-360度)
    -->

    <Button
        android:id="@+id/btn_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintCircle="@id/btn_1"
        app:layout_constraintCircleAngle="30"
        app:layout_constraintCircleRadius="150dp" />

</android.support.constraint.ConstraintLayout>

效果如下:

cir_pos.png

有了这种圆形约束,为我们进行围绕某中心进行旋转,又提供了一致新的动画实现方式,只需要修改ConstraintLayout.LayoutParams的属性circleAngle就行了,比如:

var angle = 0f
val params = btn_2.layoutParams as ConstraintLayout.LayoutParams
btn_1.setOnClickListener {
    angle += 10
    params.circleAngle = angle
    btn_2.layoutParams = params
}

2: Enforcing constraints(最大最小尺寸)

首先我们要知道android:maxWidth,android:maxHeight属性在ConstraintLayout中已经不生效了
当我们控件宽高为: WRAP_CONTENT时,而且想用:maxWidth,maxHeight两个属性来约束控件最大宽高是,要按如下写法:

<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"
    tools:context=".MainActivity">

<!--
可以看出maxWidth和maxHeight在约束布局里面是不起作用的,在1.1里面就引入了WRAP_CONTENT : enforcing constraints强制约束的属性:

app:layout_constrainedWidth="true|false"
app:layout_constrainedHeight="true|false"
同时加入新的控制最大值最小值的属性:

layout_constraintWidth_min和layout_constraintHeight_min 同minWidth属性
layout_constraintWidth_max和layout_constraintHeight_max 同maxWidth属性
-->

    <!--maxWidth/Height 无效-->
    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxWidth="10dp"
        android:maxHeight="10dp"
        android:src="@mipmap/antman_2_2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"

        />

     <!--固定宽高,作为参考-->
    <ImageView
        android:id="@+id/image2"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/antman_2_2"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"

        />

     <!--约束 宽高-->
    <ImageView
        android:id="@+id/image3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/antman_2_2"

        app:layout_constrainedWidth="true"
        app:layout_constrainedHeight="true"
        app:layout_constraintWidth_max="50dp"
        app:layout_constraintHeight_max="50dp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"

        />
</android.support.constraint.ConstraintLayout>

效果如下:

constrainted_width_height.png

可以看出在image1里,maxWidthmaxHeight在约束布局里不起作用了,在1.1.x版本里,引入了wrap_content:enforcing constraints强制约束属性:

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

同时,加入新的控制最大/最小宽高的属性:

  • layout_constraintWidth_minlayout_constraintHeight_min属性 同minWidth属性,约束最小宽高
  • layout_constraintWidth_maxlayout_constraintHeight_max属性 同maxWidth属性,约束最大宽高

设置新的属性后,显示效果同image3,可以看到,效果同其他布局里的max/minSize是一致的

3:MATCH_CONSTRAINT dimensions(按比例设置尺寸)

还记得我们之前在ConstraintLayout里是如何实现一个控件占满屏幕宽度一半的吗?,是通过GuideLine实现的

在1.1.x之后,添加了3个属性,来实现对MATCH_CONSTRAINT属性的宽高控制:

  • layout_constraintWidth_minlayout_constraintHeight_min属性 同minWidth属性,约束最小宽高
  • layout_constraintWidth_maxlayout_constraintHeight_max属性 同maxWidth属性,约束最大宽高
  • layout_constraintWidth_percentlayout_constraintHeight_percent,按百分比 设置 长宽

下面实现一个控件占满屏幕宽度一半:

<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"
    tools:context=".MainActivity">

    <!--
    
    在1.1之后添加了三个属性,来实现对MATCH_CONSTRAINT属性的宽高控制:
    
    layout_constraintWidth_min和layout_constraintHeight_min 同minWidth属性
    layout_constraintWidth_max和layout_constraintHeight_max 同maxWidth属性
    layout_constraintWidth_percent和layout_constraintHeight_percent 根据父布局的百分百设置长款
    现在我们实现一个控件实现占屏幕宽度的一半,是什么样子的呢?
    -->

    <Button
        android:id="@+id/btn1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 1------------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.5" />


    <Button
        android:id="@+id/btn2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 1------------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn1"
        app:layout_constraintWidth_max="100dp" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="bo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn2"
        app:layout_constraintWidth_min="200dp" />

    <Button
        android:id="@+id/btn4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="bo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn3" />

</android.support.constraint.ConstraintLayout>

我们看上面的btn1,通过app:layout_constraintWidth_percent="0.5",实现了宽度为屏幕宽度的一半,无论文字内容长短,宽度一直是屏幕一半的
这种实现方法,是否比GuideLine的实现简单多呐?

上面的 btn2是对app:layout_constraintWidth_max最大宽度的约束,无论内容多么多,宽度最大不超过约束的100dp
上面btn3是对最小宽度的约束,无论内容多么少,宽度都不会小于约束的200dp
btn3是作为参照,不设置任何关于MATCH_CONSTRAINT约束

layout_constraintWidth_default实现 WRAP_CONTENT的效果:
layout_constraintWidth_default的默认值是spread


    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 1-------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
/>
    <Button
        android:id="@+id/btn2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 2---------------------------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintWidth_default="spread"
        app:layout_constraintWidth_percent="0.5" />


    <Button
        android:id="@+id/btn3"


        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 3------------------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn2"
        app:layout_constraintEnd_toEndOf="parent"

        app:layout_constraintWidth_percent="0.5"
 />

    <Button
        android:id="@+id/btn4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 4-----------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintWidth_default="wrap"
        app:layout_constraintWidth_percent="0.5"
        />


    <Button
        android:id="@+id/btn5"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 5-------------------------------------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintWidth_default="wrap"
        />
    <Button
        android:id="@+id/btn6"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button 6---------------"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintWidth_default="spread"
        />
<!--
    app:layout_constraintWidth_default="wrap"
    spred
    percent
-->

</android.support.constraint.ConstraintLayout>
  • 1: btn1 -> 默认情况

  • 2: btn2 和 btn3 -> constraintWidth_default默认值是sperate,
    seperate 或不写 + percent 可以固定宽高百分比

  • 3: btn4 ->constraintWidth_default 设为wrap 会使 persent失效,变成wrap_content 的模式

  • 4: btn5 -> width=0dp + wrap能实现 wrap_content的模式

  • 5: btn6 -> width=0dp + spread 能实现match_parent的模式

4:Margins and chains(链中的margin)

在1.1之后,Chains里设置maring属性时,margin值死可以叠加的

<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"
    tools:context=".MainActivity">


    <!--
        在1.1之后,Chains里面设置margin属性的时候,值是可以叠加的
    -->

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 1"
        app:layout_constraintHorizontal_chainStyle="packed"
        android:layout_marginEnd="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn2"
        
        />


    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 2"
        app:layout_constraintHorizontal_chainStyle="packed"
        android:layout_marginStart="10dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/btn1"

 />
    
</android.support.constraint.ConstraintLayout>
margin_chain.png

5:Barrier

Barrier(屏障)与GuideLine类似,也属于Virtual Helper objects,其属性有:

  • barrierDirection屏障生效方向,值为:top,bottom,start,end,left,right

  • constraint_referenced_ids屏障基于哪些控件生成,多个id,用 逗号 隔开

  • barrierAllowsGoneWidgets 当控制的控件被设置为GONE的时候,则屏障创建会在GONE掉控件已解析的位置上进行创建,默认是true。

笔者注: barrierAllowsGoneWidgets属性,在使用过程中,并没有发现到底有什么用,这个有待更新

barrer_1.png

假设有3个控件ABC,C在AB的右边,但是AB的宽是不固定的,这个时候C无论约束在A的右边或者B的右边都不对。当出现这种情况可以用Barrier来解决。Barrier可以在多个控件的一侧建立一个屏障,如下所示:

barrer_2.png

这个时候C只要约束在Barrier的右边就可以了,代码如下:

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

    <!--
    此部分 参照:
    https://www.jianshu.com/p/17ec9bd6ca8a
    4.辅助工具
    4.2 Barrier

    https://www.jianshu.com/p/a74557359882
    6、Barrier

    -->

    <TextView
        android:id="@+id/text1"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:text="TextView1"
        android:background="@color/colorAccent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <TextView
        android:id="@+id/text2"
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:text="TextView2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text1"
        />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierAllowsGoneWidgets="false"
        app:barrierDirection="right"
        app:constraint_referenced_ids="text1,text2" />


    <TextView
        android:id="@+id/text3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView3"
        app:layout_constraintLeft_toRightOf="@id/barrier"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="10dp"
        />

</android.support.constraint.ConstraintLayout>
barrer_show.png

6:Group

Group 可以吧多个控件归为一组,方便隐藏或显示一组控件时,统一调用

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:app1="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--
Group
Group与Barrier一样,也是属于Virtual Helper objects。顾名思义,Group一个组的控件,通过设置一组的控件id,来达到分组的目的。
想想这样的情况,在我们针对多个控件进行显示隐藏的时候,通常要写很多的setVisibility的代码,但是在1.1之后,直接设置Group的显示和隐藏就可以了。
    -->

    <TextView
        android:id="@+id/text1"
        android:background="#a9b3a9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="10dp"
        android:text="TextView1" />

    <TextView
        android:id="@+id/text2"
        android:background="#a9b3a9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="TextView2"
        app:layout_constraintStart_toEndOf="@id/text1" />

    <TextView
        android:id="@+id/text3"
        android:background="#a9b3a9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="TextView3"
        app1:layout_constraintStart_toEndOf="@id/text2" />

    <android.support.constraint.Group
        android:id="@+id/group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="text1,text3" />

</android.support.constraint.ConstraintLayout>

我们用Group把TextView1TextView3归为一组,再控制这组控件的可见性,效果如下:

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

推荐阅读更多精彩内容