转自:
ConstraintLayout 1.1版本的新特性
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>
效果如下:
有了这种圆形约束,为我们进行围绕某中心进行旋转,又提供了一致新的动画实现方式,只需要修改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>
效果如下:
可以看出在image1
里,maxWidth
和maxHeight
在约束布局里不起作用了,在1.1.x版本里,引入了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
属性,约束最大宽高
设置新的属性后,显示效果同image3
,可以看到,效果同其他布局里的max/minSize
是一致的
3:MATCH_CONSTRAINT dimensions(按比例设置尺寸)
还记得我们之前在ConstraintLayout里是如何实现一个控件占满屏幕宽度一半的吗?,是通过GuideLine
实现的
在1.1.x之后,添加了3个属性,来实现对MATCH_CONSTRAINT
属性的宽高控制:
-
layout_constraintWidth_min
和layout_constraintHeight_min
属性 同minWidth
属性,约束最小宽高 -
layout_constraintWidth_max
和layout_constraintHeight_max
属性 同maxWidth
属性,约束最大宽高 -
layout_constraintWidth_percent
和layout_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>
5:Barrier
Barrier
(屏障)与GuideLine
类似,也属于Virtual Helper objects
,其属性有:
barrierDirection
屏障生效方向,值为:top,bottom,start,end,left,right
constraint_referenced_ids
屏障基于哪些控件生成,多个id,用 逗号 隔开barrierAllowsGoneWidgets
当控制的控件被设置为GONE
的时候,则屏障创建会在GONE
掉控件已解析的位置上进行创建,默认是true。
笔者注:
barrierAllowsGoneWidgets
属性,在使用过程中,并没有发现到底有什么用,这个有待更新
假设有3个控件ABC,C在AB的右边,但是AB的宽是不固定的,这个时候C无论约束在A的右边或者B的右边都不对。当出现这种情况可以用Barrier来解决。Barrier可以在多个控件的一侧建立一个屏障,如下所示:
这个时候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>
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把TextView1
和TextView3
归为一组,再控制这组控件的可见性,效果如下:
text1.setOnClickListener {
group.visibility = if (group.visibility == View.VISIBLE) View.GONE else View.VISIBLE
}