简介
ConstraintLayout是谷歌2016年的I/O大会上推出的新控件,Constraint翻译过来就是“约束”的意思,这个控件跟RelativeLayout类似,其子控件通过互相约束来确定位置、大小,但是比RelativeLayout的功能强大很多。使用这个控件作为根布局,可以实现很复杂的布局情况,以前需要嵌套多层才能实现的布局,现在可能一层就够了。
谷歌的演示侧重引导开发者通过鼠标拖控件的方式来写布局,ConstraintLayout也是比较好的支持了鼠标拖动布局,也有不少相关博客主要以拖动讲解为主。但是还是有一些属性无法通过鼠标拖动来完成,比如设置visible、尺寸单位(dp、px)等,所以我想,与其学习“可视化操作布局+xml代码布局”,还不如直接学习“xml代码布局”。
要使用这个控件首先要在gralde中导入,如下:
dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
其次,在layout布局文件中要引入自定义属性的命名空间:xmlns:app=”http://schemas.android.com/apk/res-auto”,这样下面的控件才能使用其中的自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
这篇博客分为四部分来讲解ConstraintLayout:
1、第一部分讲解ConstraintLayout中的子控件是如何确定位置的;
2、第二部分讲解子控件是如何确定自身尺寸的;
3、第三部分讲解chains链条特性,非常实用;
4、第四部分讲解一些其它属性;
控件位置
一、基本控制
主要有8个属性来设置控件的位置,跟RelativeLayout差不多:
// 左边向parent父控件的左边靠拢(注意,这里用的是“靠拢”,而不是“对齐”,后面就能体会到了)
app:layout_constraintLeft_toLeftOf="parent"
// 左边向btn2的右边靠拢。也就是再btn2的右边,相当于RelativeLayout的toRightOf
app:layout_constraintLeft_toRightOf="@+id/btn2"
// 下面的6个属性就不一一注释了,参照上面两个,一眼就能看懂
app:layout_constraintTop_toBottomOf=""
app:layout_constraintTop_toTopOf=""
app:layout_constraintRight_toLeftOf=""
app:layout_constraintRight_toRightOf=""
app:layout_constraintBottom_toBottomOf=""
app:layout_constraintBottom_toTopOf=""
在一个水平上设置一个约束是很清楚的,就跟RelativeLayout的toRightOf等属性效果一样,但是如果一个水平上设置两个约束呢?比如下面:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
这就是为什么前面为什么要用“靠拢”这个词了,也可以理解这个控件为什么叫“约束控件”,这些属性都不是绝对的,只是一种约束,控件的最终位置(其他属性也一样)是通过各种约束条件来决定的,而不是像RelativieLayout的toRightOf那样一锤子买卖。
上面的意思就是左边尽量向parent的左边靠拢,右边尽量向parent的右边靠拢,最终就会取一个中间状态,让控件同时满足这两个约束条件,所以这个button最终是居中的。你可以脑补一下,一个力向左边拉,一个相等的力同时向右边拉,所以你最终在中间了。
二、偏向性控制
ConstraintLayout还有个很好用的属性app:layout_constraintHorizontal_bias=”0.1”,用来设置控件位置的偏向性,直接用代码说明:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
可以这么理解,btn既要向左边靠拢,有要向右边靠拢,然后就取了折中方案居中了。现在设置了layout_constraintHorizontal_bias约束,所以在满足前面两个约束的前提下,还要继续满足第三个约束。这个约束的意思是,在水平方向上,离左边的距离为0.2份,离右边的距离0.8份,也就是离左边更近一些。通过设置这个值,能轻松控制控件的相对于parent、其它控件的位置。
竖直方向的属性是app:layout_constraintVertical_bias=”0.3”,与上面同理,就不展开了。
尺寸设置
尺寸的设置主要有三种方式:通用的属性设置、约束条件设置、宽高比例设置
一、通用属性设置
1、设置具体值
与其它layout一样,设置android:layout_width=”100dp”就可以了。
2、由内容控制
与其它layout一样,设置android:layout_width=”wrap_content”。
二、约束条件设置
设置android:layout_width=”0dp”,意思就是由约束条件控制。举两个例子就明白了:
// 宽度设置为0dp,约束条件既要向parent左边靠拢,又要向parent右边靠拢,结果就是match_parent了
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
// 宽度设置为0dp,约束条件既要向btn1的左边靠拢,又要向btn1的右边靠拢,结果就是与btn1宽度一样
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="@+id/btn1"
app:layout_constraintLeft_toLeftOf="@+id/btn1"/>
注意:如果只是单纯地设置为0dp,而没有其它约束条件来约束尺寸,最终效果就是wrap_content,可以理解为,在没有其它约束条件时,wrap_content就成了唯一约束条件。
三、宽高比例设置
其实这个也属于“约束条件设置”,只是这里的约束条件变成了宽高比例。
ConstraintLayout有个app:layout_constraintDimensionRatio=”2:1”属性,用于控制宽高比例,前面的数字是宽,后面数字是高。
要使这个属性生效,需要要满足两个条件:
1、宽高属性中其中一个属性由约束条件设置,也就是设置为0dp,并且设置了Right_toRight和Left_toLeft属性;
2、另一个属性不能为0dp(从实际使用效果来看,最好设置为固定值,设置为wrap_content的效果很奇怪);
看下代码示例就理解了:
// 最终的效果就是宽是高的2倍。如果height设置为wrap_content,然后通过设置text属性设置内容,最终效果也确实是宽是高的2倍,但是text的内容会换行。。。效果不尽人意。
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
Chains链条布局
链条就是一系列控件在同一水平上首位相连,形成一个整体。实现链条需要满足两个条件:
1、btn1设置靠拢btn2左边,同时btn2要设置靠拢btn1右边,两个控件都要设置属性;
2、最左边的btn要设置靠拢parent左边,最右边的btn要设置靠拢parent右边;
形成chains链条后,这个chains就是一个整体了,通过对head头(该链条上的第一个控件)设置app:layout_constraintHorizontal_chainStyle=”“属性,能够设置这个链条样式。
下面是官网上显示的各种样式链条的效果图:
这5个样式分为三类,一类是直接通过style属性设置(样式1、2、4),一类是通过权重设置(样式3),最后一类是通过bias属性设置(样式5)。
一、style属性设置
通过对head头控件设置app:layout_constraintHorizontal_chainStyle属性,可以显示出上面样式1、2、4的效果:
<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">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
app:layout_constraintHorizontal_chainStyle="spread" // 对应样式1(默认样式)
app:layout_constraintHorizontal_chainStyle="spread_inside" // 对应样式2
app:layout_constraintHorizontal_chainStyle="packed" // 对应样式4
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" // 最左边的链条靠拢parent左边
app:layout_constraintRight_toLeftOf="@+id/btn2" />
// 可以看到,btn1靠拢btn2的左边,btn2靠拢btn1的右边,同样btn2和btn3也是如此
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintRight_toLeftOf="@+id/btn3" />
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent" //最右边的链条靠拢parent右边
app:layout_constraintLeft_toRightOf="@+id/btn2" />
</android.support.constraint.ConstraintLayout>
二、权重链
第3种样式是加权链,在链条样式为spread的情况下,通过设置btn的app:layout_constraintHorizontal_weight=”“属性来控制btn宽度,跟LinearLayout是一样的,也需要把宽度设置为0dp,代码如下:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content" // 不需要由weight决定宽
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn2" />
<Button
android:id="@+id/btn2"
android:layout_width="0dp" // width设置为0,让weight决定宽度
android:layout_height="wrap_content"
app:layout_constraintHorizontal_weight="1" // 占剩下空间的1份
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintRight_toLeftOf="@+id/btn3" />
<Button
android:id="@+id/btn3"
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1" //也占1份,所以剩下空间要与btn2平分
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn2"
app:layout_constraintRight_toRightOf="parent"/>
三、bias链条
在链条样式是packed的情况下,通过设置head头控件的bias属性,来设置链条的位置(更偏向左或更偏向右)
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_bias="0.3" // 权重为靠左0.3
app:layout_constraintHorizontal_chainStyle="packed" // 样式为packed
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn2" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintRight_toLeftOf="@+id/btn3" />
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn2"
app:layout_constraintRight_toRightOf="parent" />
其它属性
一、app:layout_goneMarginLeft=”50dp”
这个属性的意思是,如果左边的控件是可见的,这个属性不生效;如果左边控件设置为gone,这个属性就会生效,离左边间隔50dp。
这个属性与android:layout_marginLeft=”“属性不冲突,可以同时生效。
二、android.support.constraint.Guideline控件
这是一条基准线,没有内容、不会显示、draw方法都是空实现,它的作用就是辅助我们进行控件定位。
android:orientation=”vertical”属性用来设置基准线的方向,垂直线或水平线;
app:layout_constraintGuide_percent=”0.7”属性或android:layout_margin=”“属性用来设置它的位置,percent=0.7就是离父控件左边/上边70%距离,margin=100dp就是离父控件左边/上边100dp
确定了它的方向和位置,我们就可以通过它来定位,设置其它控件的位置了
<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">
<android.support.constraint.Guideline
android:id="@+id/line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" // 设置方向和位置
app:layout_constraintGuide_percent="0.7"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/line"/>
</android.support.constraint.ConstraintLayout>
大致的使用就是这些了,只用这个控件,很多布局都变得方便了,嵌套层级减少不是一点两点,视图加载效率也会高很多。