当前手机APP项目中,有些界面比较复杂,导致布局层次很深,View的数量也相当多,对性能产生了一定影响;复杂的布局,同时也增大了代码维护的难度。
ConstraintLayout 正是为了解决这个问题,它支持以下几类强大的特性:
- 相对定位
Margins
中心定位
角度定位
Visibility behavior
尺寸约束
链(Chains)
Virtual Helpers objects
在组合使用这些特性以后,我们可以达到明显降低布局层次的目的。
在module的build.gradle中插入:
dependencies {
...
//引入ConstraintLayout
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
...
}
目前最新版本为1.1.0-beta3
相对定位是ConstrainLayout中最为经常使用的一项属性,它支持
水平方向:
app:layout_constraintLeft_toLeftOf
app:layout_constraintLeft_toRightOf
app:layout_constraintRight_toLeftOf
app:layout_constraintRight_toRightOf
app:layout_constraintStart_toEndOf
app:layout_constraintStart_toStartOf
app:layout_constraintEnd_toStartOf
app:layout_constraintEnd_toEndOf
竖直方向:
app:layout_constraintTop_toTopOf
app:layout_constraintTop_toBottomOf
app:layout_constraintBottom_toTopOf
app:layout_constraintBottom_toBottomOf
app:layout_constraintBaseline_toBaselineOf
这些属性都需要引用到另一个控件,或者parent(指代他们的父容器,也就是ConstraintLayout)
跟其它布局所不同的是,ConstraintLayout还支持链接到Visibility为Gone时的Margin:
layout_goneMarginLeft
layout_goneMarginRight
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginTop
layout_goneMarginBottom
我们看一下这种情况:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
>
Button两端都被链接到了父容器的两端,如果
1. Button刚好和父容器相同宽度时,Button就相当于宽度设为了match_parent;
在中心定位时,我们可以对这两个约束力进行控制,使其偏向某一侧。例如,我们使控件偏向左侧:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
>
正如你所见,这有点类似于百分比布局或LinearLayout的weight属性,这使得我们可以更好地适应不同的屏幕尺寸。
角度定位是ConstraintLayout所特有的一种布局方式,它可以约束一个控件的中心相对于另一个的角度和距离。你可以通过使用这些属性达到目的:
layout_constraintCircle: 角度定位相对的另一个控件的id
layout_constraintCircleAngle: 控件相对于另一个控件的角度
示例代码:
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />
如果控件与控件间存在约束关系,当其中的一个控件Visibility变为GONE时,ConstraintLayout仍然会保留这个约束关系,但这个View的Margin都会失效;这样可以确保不会影响到已有的布局。
ConstraintLayout可以为布局设置宽高(android:layout_width 、android:layout_height),需要特殊注意的是,当设为0dp时,它的作用相当于MATCH_CONSTRAINT,而MATCH_PARENT在ConstraintLayout中是不被推荐使用的。
ConstraintLayout可以对布局的高度和宽度进行限制:
- android:minWidth:最小宽度
android:minHeight:最小高度
android:maxWidth:最大宽度
android:maxHeight:最大高度
注意:这些属性仅在宽高设为WRAP_CONTENT时有效!
在ConstraintLayout中,仍然可以对WRAP_CONTENT的最大尺寸进行约束:
- app:layout_constrainedWidth=”true|false”
当其中一个被设置为true时,控件的最大宽高任然可以被约束链约束,需要注意的是,这样做会使布局变慢一些。
当宽高被设为MATCH_CONSTRAINT,这个控件将尝试占据布局上所有可用的地方,但同时会被这些属性所限制:
- layout_constraintWidth_min/layout_constraintHeight_min:最小宽高
layout_constraintWidth_max/layout_constraintHeight_max:最大宽高
layout_constraintWidth_percent/layout_constraintHeight_percent:宽高相对于父容器的百分比。
注意:
1. 这些属性同时可以设置为wrap;
当使用百分比尺寸的时候,应当设置宽高为MATCH_CONSTRAINT;
父容器需要设置app:layout_constraintWidth_default=”percent”或app:layout_constraintHeight_default=”percent”(在1.1-beta2以后不再必须设置)
5. 设置比例
constraintLayout支持子控件设置其宽高比,要使该特性生效至少需要将宽高中的一个设置为0dp(MATCH_CONSTRAINT)
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
app:layout_constraintDimensionRatio可以设置为两种格式:
1. 一个float类型的数值,代表宽与高之间的比例;
注意:
当宽高均被设为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"/>
链使我们能够对一组在水平或竖直方向互相关联的控件的属性进行统一管理。成为链的条件是:一组控件他们通过一个双向的约束关系链接起来。
注意:链的属性是由一条链的头结点控制的。而头结点的定义是一条链中位于最左端的控件。
ConstraintLayout支持对链添加Margin,如果这条链的控件是分散分布的,将会从已分配给链的空间中减去设置的链边距。
链支持设置他们的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属性,那么他们将根据所设置的比重来分配剩下的空间。
虚拟辅助类部件它们最终不会在界面上呈现出来,但可以帮助我们更好更精细地控制布局。目前。所支持的这类部件包括:
Guideline可以放在竖直方向或水平方向,水平Guideline的高为0,宽度与父容器一致;竖直Guideline同理。
Guideline 具有三类特殊的属性:
- layout_constraintGuide_begin:设置Guideline 距离父容器起始位置的距离(left或top);
layout_constraintGuide_end:设置Guideline 距离父容器尾部的距离(right或bottom);
layout_constraintGuide_percent:设置Guideline 相对于父容器宽度/高度的百分比位置。
例如,设置一条竖直方向的Guideline:
<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">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"/>
android.support.constraint.ConstraintLayout>
Barrier 使用多个控件作为参考,在这些控件中,选取在特定方向最边缘的的控件创建一条Guideline。
constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。
例如,假设已有两个按钮:
Barrier 设置为:
<android.support.constraint.Barrier
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="bt_1,bt_2"/>
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中的定义顺序将决定这个控件最终的可见性。