约束布局ConstraintLayout 是一个ViewGroup,能够在Api9以上的Android系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。从 Android Studio 2.3 起,官方的模板默认使用 ConstraintLayout。android
在开发过程当中常常能遇到一些复杂的UI,可能会出现布局嵌套过多的问题,嵌套得越多,设备绘制视图所需的时间和计算功耗也就越多。简单举个例子:微信
假设如今要写一个这样的布局,可能有人会这么写: 首先是一个垂直的LinearLayout,里面放两个水平的LinearLayout,而后在水平的LinearLayout里面放TextView。这样的写法就嵌套了两层LinearLayout。app
有些人考虑到了嵌套布局带来的风险,因此用一个RelativeLayout来装下全部的控件。那么问题来了,既然用RelativeLayout能够解决问题,为何还要使用ConstraintLayout呢?由于ConstraintLayout使用起来比RelativeLayout更灵活,性能更出色!还有一点就是ConstraintLayout能够按照比例约束控件位置和尺寸,可以更好地适配屏幕大小不一样的机型。编辑器
首先咱们须要在app/build.gradle文件中添加ConstraintLayout的依赖,以下所示。ide
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
复制代码
相对定位是部件对于另外一个位置的约束,这么说可能有点抽象,举个例子:工具
如图所示,TextView2在TextView1的右边,TextView3在TextView1的下面,这个时候在布局文件里面应该这样写:布局
<TextView
android:id="@+id/TextView1"
...
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1" />
<TextView
android:id="@+id/TextView3"
...
app:layout_constraintTop_toBottomOf="@+id/TextView1" />
复制代码
上面代码中在TextView2里用到了app:layout_constraintLeft_toRightOf="@+id/TextView1"这个属性,他的意思是把TextView2的左边约束到TextView1的右边,以下图所示:性能
同理TextView3在TextView1的下面,就须要用到app:layout_constraintTop_toBottomOf="@+id/TextView1",即把TextView3的上面约束到TextView1的下面。学习
下面来看看相对定位的经常使用属性: 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
上面属性中有一个比较有趣的layout_constraintBaseline_toBaselineOf Baseline指的是文本基线,举个例子:
如图所示,两个TextView的高度不一致,可是又但愿他们文本对齐,这个时候就可使用layout_constraintBaseline_toBaselineOf,代码以下:
<TextView
android:id="@+id/TextView1"
.../>
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintBaseline_toBaselineOf="@+id/TextView1"/>
复制代码
效果以下:
ConstraintLayout相对定位的用法跟RelativeLayout仍是比较类似的,下面用一个图来总结相对定位:
角度定位指的是能够用一个角度和一个距离来约束两个空间的中心。举个例子:
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintCircle="@+id/TextView1"
app:layout_constraintCircleAngle="120"
app:layout_constraintCircleRadius="150dp" />
复制代码
上面例子中的TextView2用到了3个属性: app:layout_constraintCircle="@+id/TextView1" app:layout_constraintCircleAngle="120"(角度) app:layout_constraintCircleRadius="150dp"(距离) 指的是TextView2的中心在TextView1的中心的120度,距离为150dp,效果以下:
ConstraintLayout的边距经常使用属性以下: android:layout_marginStart android:layout_marginEnd android:layout_marginLeft android:layout_marginTop android:layout_marginRight android:layout_marginBottom
看起来跟别的布局没有什么差异,但实际上控件在ConstraintLayout里面要实现margin,必须先约束该控件在ConstraintLayout里的位置,举个例子:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp" />
</android.support.constraint.ConstraintLayout>
复制代码
若是在别的布局里,TextView1的位置应该是距离边框的左边和上面有一个10dp的边距,可是在ConstraintLayout里,是不生效的,由于没有约束TextView1在布局里的位置。正确的写法以下:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
复制代码
把TextView1的左边和上边约束到parent的左边和上边,这样margin就会生效,效果以下:
在使用margin的时候要注意两点: 控件必须在布局里约束一个相对位置 margin只能大于等于0
goneMargin主要用于约束的控件可见性被设置为gone的时候使用的margin值,属性以下: layout_goneMarginStart layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginTop layout_goneMarginRight layout_goneMarginBottom
举个例子: 假设TextView2的左边约束在TextView1的右边,并给TextView2设一个app:layout_goneMarginLeft="10dp",代码以下:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/TextView1"
.../>
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_goneMarginLeft="10dp"
/>
</android.support.constraint.ConstraintLayout>
复制代码
效果以下,TextView2在TextView1的右边,且没有边距。
这个时候把TextView1的可见性设为gone,效果以下:
TextView1消失后,TextView2有一个距离左边10dp的边距。
在RelativeLayout中,把控件放在布局中间的方法是把layout_centerInParent设为true,而在ConstraintLayout中的写法是:
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
复制代码
意思是把控件的上下左右约束在布局的上下左右,这样就能把控件放在布局的中间了。同理RelativeLayout中的水平居中layout_centerHorizontal至关于在ConstraintLayout约束控件的左右为parent的左右;RelativeLayout中的垂直居中layout_centerVertical至关于在ConstraintLayout约束控件的上下为parent的上下。 因为ConstraintLayout中的居中已经为控件约束了一个相对位置,因此可使用margin,以下所示:
<TextView
android:id="@+id/TextView1"
...
android:layout_marginLeft="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
复制代码
效果以下:
上面TextView1在水平居中后使用layout_marginLeft="100dp"向右偏移了100dp。除了这种偏移外,ConstraintLayout还提供了另一种偏移的属性: layout_constraintHorizontal_bias 水平偏移 layout_constraintVertical_bias 垂直偏移
举个例子:
<TextView
android:id="@+id/TextView1"
...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
复制代码
效果以下:
假如如今要实现水平偏移,给TextView1的layout_constraintHorizontal_bias赋一个范围为 0-1 的值,假如赋值为0,则TextView1在布局的最左侧,假如赋值为1,则TextView1在布局的最右侧,假如假如赋值为0.5,则水平居中,假如假如赋值为0.3,则更倾向于左侧。 垂直偏移同理。
控件的尺寸能够经过四种不一样方式指定:
使用指定的尺寸
使用wrap_content,让控件本身计算大小 当控件的高度或宽度为wrap_content时,可使用下列属性来控制最大、最小的高度或宽度: android:minWidth 最小的宽度 android:minHeight 最小的高度 android:maxWidth 最大的宽度 android:maxHeight 最大的高度 注意!当ConstraintLayout为1.1版本如下时,使用这些属性须要加上强制约束,以下所示: app:constrainedWidth=”true” app:constrainedHeight=”true”
使用 0dp (MATCH_CONSTRAINT) 官方不推荐在ConstraintLayout中使用match_parent,能够设置 0dp (MATCH_CONSTRAINT) 配合约束代替match_parent,举个例子:
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:visibility="visible" />
复制代码
宽度设为0dp,左右两边约束parent的左右两边,并设置左边边距为50dp,效果以下:
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
复制代码
宽设置为0dp,宽高比设置为1:1,这个时候TextView1是一个正方形,效果以下:
除此以外,在设置宽高比的值的时候,还能够在前面加W或H,分别指定宽度或高度限制。 例如: app:layout_constraintDimensionRatio="H,2:3"指的是 高:宽=2:3 app:layout_constraintDimensionRatio="W,2:3"指的是 宽:高=2:3
若是两个或以上控件经过下图的方式约束在一块儿,就能够认为是他们是一条链(图为横向的链,纵向同理)。
用代码表示:
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent" />
复制代码
3个TextView相互约束,两端两个TextView分别与parent约束,成为一条链,效果以下:
一条链的第一个控件是这条链的链头,咱们能够在链头中设置 layout_constraintHorizontal_chainStyle来改变整条链的样式。chains提供了3种样式,分别是: CHAIN_SPREAD —— 展开元素 (默认); CHAIN_SPREAD_INSIDE —— 展开元素,但链的两端贴近parent; CHAIN_PACKED —— 链的元素将被打包在一块儿。 如图所示:
上面的例子建立了一个样式链,除了样式链外,还能够建立一个权重链。 能够留意到上面所用到的3个TextView宽度都为wrap_content,若是咱们把宽度都设为0dp,这个时候能够在每一个TextView中设置横向权重layout_constraintHorizontal_weight(constraintVertical为纵向)来建立一个权重链,以下所示:
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2"
app:layout_constraintHorizontal_weight="2" />
<TextView
android:id="@+id/TextView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="3" />
<TextView
android:id="@+id/TextView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="4" />
复制代码
效果以下:
当咱们使用 MATCH_CONSTRAINT 时,ConstraintLayout 将对控件进行 2 次测量,ConstraintLayout在1.1中能够经过设置 layout_optimizationLevel 进行优化,可设置的值有: none:无优化 standard:仅优化直接约束和屏障约束(默认) direct:优化直接约束 barrier:优化屏障约束 chain:优化链约束 dimensions:优化尺寸测量
假设有3个控件ABC,C在AB的右边,可是AB的宽是不固定的,这个时候C不管约束在A的右边或者B的右边都不对。当出现这种状况能够用Barrier来解决。Barrier能够在多个控件的一侧创建一个屏障,以下所示:
这个时候C只要约束在Barrier的右边就能够了,代码以下:
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/TextView1" />
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="TextView1,TextView2" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/barrier" />
复制代码
app:barrierDirection为屏障所在的位置,可设置的值有:bottom、end、left、right、start、top app:constraint_referenced_ids为屏障引用的控件,可设置多个(用“,”隔开)
Group能够把多个控件归为一组,方便隐藏或显示一组控件,举个例子:
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView1" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/TextView2" />
复制代码
如今有3个并排的TextView,用Group把TextView1和TextView3归为一组,再设置这组控件的可见性,以下所示:
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:constraint_referenced_ids="TextView1,TextView3" />
复制代码
效果以下:
Placeholder指的是占位符。在Placeholder中可以使用setContent()设置另外一个控件的id,使这个控件移动到占位符的位置。举个例子:
<android.support.constraint.Placeholder
android:id="@+id/placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:content="@+id/textview"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#cccccc"
android:padding="16dp"
android:text="TextView"
android:textColor="#000000"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
复制代码
新建一个Placeholder约束在屏幕的左上角,新建一个TextView约束在屏幕的右上角,在Placeholder中设置 app:content="@+id/textview",这时TextView会跑到屏幕的左上角。效果以下:
Guildline像辅助线同样,在预览的时候帮助你完成布局(不会显示在界面上)。 Guildline的主要属性: android:orientation 水平vertical,垂直horizontal layout_constraintGuide_begin 开始位置 layout_constraintGuide_end 结束位置 layout_constraintGuide_percent 距离顶部的百分比(orientation = horizontal时则为距离左边) 举个例子:
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="50dp" />
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
复制代码
guideline1为水平辅助线,开始位置是距离顶部50dp,guideline2位垂直辅助线,开始位置为屏幕宽的0.5(中点位置),效果以下:
本篇文章主要介绍了ConstraintLayout和它在布局文件里的用法,和一些辅助ConstraintLayout布局的工具,跟着敲一遍就能学会ConstraintLayout。除此以外,ConstraintLayout还有一个独立的编辑器,只须要托拉拽就能够完成整个布局,但我我的比较喜欢直接用代码写,就不介绍了,有兴趣的能够参考https://blog.csdn.net/guolin_blog/article/details/53122387
微信扫描下方二维码关注微信公众号"AndroidCzh"一块儿学习ConstraintLayout吧!这里将长期为您分享原创文章、Android开发经验等!