一、简介
ConstraintLayout
翻译为 约束布局,也有人把它称作 增强型的相对布局,由 2016 年 Google I/O 推出。扁平式的布局方式,无任何嵌套,减少布局的层级,优化渲染性能。从支持力度而言,将成为主流布局样式,完全代替其他布局。有个成语用的非常好,集万千宠爱于一身,用到这里非常合适,约束集 LinearLayout(线性布局),RelativeLayout(相对布局),百分比布局等的功能于一身,功能强大,使用灵活。
二、使用
在项目的build.gradle
引入constraint-layout
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
布局文件中使用
<?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="match_parent">
……
</android.support.constraint.ConstraintLayout>
三、约束详解
3.1、相对定位
相对定位是在ConstraintLayout中创建布局的基本构建块之一。设置控件与另一个控件的相对位置,您可以在水平和垂直轴上约束小部件:
- 水平轴:Left、Right、Start、End
- 垂直轴:top、bottom、text baseline
一般概念是将窗口小部件的给定侧约束到任何其他窗口小部件的另一侧。
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA" />
这告诉系统我们希望按钮B的左侧被约束到按钮A的右侧。这样的位置约束意味着系统将尝试让双方共享相同的位置。
以下是可用约束的列表(如上图):
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
以上属性需要另一个控件的id
或parent
(父容器)作为参考.
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
app:layout_constraintTop_toBottomOf="@id/buttonB"
android:layout_height="wrap_content"
android:text="A(我在B下方)" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B(我在右上角)"
app:layout_constraintRight_toRightOf="parent" />
3.2、边距(Margin)
如果设置了边距,则它们将应用于相应的约束(如果存在)(如上图),将边距强制为目标和源边之间的空间。通常的布局边距属性可用于此效果:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
请注意,单位只能是正数或等于零,并且需要一个Dimension
。
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dip"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA" />
边距失效(Margin间距失效)
具体顶部100dip
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dip"
android:text="A" />
如上设置了android:layout_marginTop="100dip"
但是失效,应为设置某一边的边距则需要设置某一边的约束目标对象(比如这里是parent)
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dip"
android:text="A"
app:layout_constraintTop_toTopOf="parent" />
此时设置android:layout_marginTop="100dip"
生效了.
3.3、GONE(距离隐藏控件边距)
[例]: 要求控件B左边距离控件A右边20dip ,控件C紧跟控件B。当控件B设置为GONE时,控件C左边距离控件A右边20dip
控件B未隐藏时:
控件B隐藏时:
此时发现空间C紧跟空间A,没有距离控件A右边20dip,不满足需求,可以使用layout_goneMarginLeft
解决
设置layout_goneMarginLeft
以后,隐藏空间B效果如下:
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_marginLeft="20dip"
android:layout_height="wrap_content"
android:text="B"
android:visibility="gone"
app:layout_constraintLeft_toRightOf="@id/buttonA"
/>
<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_goneMarginLeft="20dip"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
/>
当位置约束目标的可见性为View.GONE
,您还可以使用以下属性指示要使用的不同边距值:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
3.4、居中定位和偏压
设置控件A横向居中:
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="A" />
偏压:
遇到这种相反的约束时的默认设置是使窗口小部件居中; 但是您可以使用偏差属性调整定位以使一侧偏向另一侧:
layout_constraintHorizontal_bias
layout_constraintVertical_bias
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
偏压值范围:0-1
3.5、圆形定位(1.1版本中增加)
您可以以角度和距离约束窗口小部件中心相对于另一个窗口小部件中心。这允许您将小部件放在圆上(如下图)。可以使用以下属性:
layout_constraintCircle
:依赖哪个控件进行布局layout_constraintCircleRadius
:到依赖对象中心的距离layout_constraintCircleAngle
:当前要摆放的控件应处于哪个角度(以度为单位,从0到360)
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="100dp"
/>
<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="100dp"
/>
<Button
android:id="@+id/buttonD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="D"
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleAngle="225"
app:layout_constraintCircleRadius="100dp"
/>
<Button
android:id="@+id/buttonE"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="E"
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleAngle="315"
app:layout_constraintCircleRadius="100dp"
/>
上例我们实现了B在45°方向摆放,并且靠近依赖约束的对象的中心点100dp,C、D、E类似,跟A间隔135°、225°、315° .
3.6、可见性行为
ConstraintLayout
具有标记为小部件的特定处理View.GONE
。
GONE
像往常一样,窗口小部件不会显示,也不是布局本身的一部分(即如果标记为,它们的实际尺寸将不会更改GONE
)。
但就布局计算而言,GONE
小部件仍然是其中的一部分,具有重要的区别:
- 对于布局传递,它们的尺寸将被视为零(基本上,它们将被解析为一个点)
- 如果他们对其他小部件有限制,他们仍然会受到尊重,但任何边距都会等于零
这种特定的行为允许构建布局,您可以暂时将窗口小部件标记为GONE
,而不会破坏布局(如上图),这在进行简单的布局动画时尤其有用。
注意 使用的边距将是B在连接到A时定义的边距(如上图)。在某些情况下,这可能不是您想要的余量(例如A在其容器侧面有100dp的边距,B只有16dp到A,A标记为已消失,B将对容器有16dp的余量)。因此,您可以指定在连接到标记为已消失的窗口小部件时要使用的备用边距值(请参阅GONE(距离隐藏控件边距)
)
3.7、尺寸限制
ConstraintLayout上的最小尺寸
您可以为ConstraintLayout
自身定义最小和最大尺寸:
android:minWidth
设置布局的最小宽度android:minHeight
设置布局的最小高度android:maxWidth
设置布局的最大宽度android:maxHeight
设置布局的最大高度
注意:这些属性仅在宽高设为WRAP_CONTENT时有效!
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="100dip"
android:text="12345678901234567890" />
3.8、控件尺寸约束
可以通过以3种不同方式设置android:layout_width
和 android:layout_height
属性来指定控件的尺寸:
- 使用特定尺寸(文字值,例如
123dp
或Dimension
参考) - 使用
WRAP_CONTENT
,这将要求控件计算自己的大小 - 使用
0dp
,相当于“MATCH_CONSTRAINT
”
前两个类似。最后一个将调整控件,以一致的约束来设置(a:wrap_content;b:0dp
)。如果设置了边距,布局计算中将会计算到(c:0dp
)。
注意:ContraintLayout中的控件不支持MATCH_PARENT,虽然类似的操作可以使用MATCH_CONSTRAINT与设置相应的left/right 或 top/bottom以parent约束。
3.9、WRAP_CONTENT:强制约束(1.1中增加)
如果将尺寸设置为WRAP_CONTENT
,则在1.1之前的版本中,它们将被视为文字尺寸 - 这意味着约束不会限制生成的尺寸。虽然通常这足够(并且更快),但在某些情况下,您可能希望使用WRAP_CONTENT
,但仍然强制执行约束以限制生成的尺寸。在这种情况下,您可以添加一个相应的属性:
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
[例1]: 要求B控件在A控件右边(并且处于A控件右侧与右侧屏幕中间),效果如下:
此时当B控件内容变多会出现B控件在A控件右侧失效情况如下:
解决方案:设置app:layout_constrainedWidth=”true”
强制约束,效果如下:
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="true"
android:text="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
app:layout_constraintLeft_toRightOf="@+id/buttonA"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/buttonA"/>
[例2]: 要求B控件紧跟A控件后面,效果如下:
此时当A控件内容变多会出现B控件右侧在屏幕右侧右侧失效情况如下(B控件被挤出屏幕):
解决方案:设置app:layout_constrainedWidth=”true”
强制约束,效果如下:
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constrainedWidth=“true” 会导致渲染变慢,变慢时长可忽略不计。
3.10、MATCH_CONSTRAINT(0dp) dimensions 填充父窗体约束(1.1中添加)
当宽高被设为MATCH_CONSTRAINT(0dp),这个控件将尝试占据布局上所有可用的地方,但同时会被这些属性所限制:
layout_constraintWidth_min
和layout_constraintHeight_min
:将设置尺寸的最小大小layout_constraintWidth_max
和layout_constraintHeight_max
:将设置尺寸的最大大小layout_constraintWidth_percent
和layout_constraintHeight_percent
:将尺寸的大小设置为父级的百分比
注意:
min和max的值可以是dp中的尺寸,也可以是“wrap”,它将使用与其相同的值WRAP_CONTENT
。当使用百分比尺寸的时候,应当设置宽高为MATCH_CONSTRAINT;父容器需要设置app:layout_constraintWidth_default=”percent”
或app:layout_constraintHeight_default=”percent”
(在1.1-beta2以后不再必须设置)
[例1]: 控件A位于父控件的中间且宽度最大为100dip
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="wrap_content"
app:layout_constraintWidth_max="100dip"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:text="AAAAAAAAAAA" />
[例2]: 控件A位于父控件的中间且宽度为父控件的一半
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.5" />
注意:要使用百分比,您需要设置以下内容:
- 尺寸应设置为
MATCH_CONSTRAINT
(0dp) - 默认值应设置为百分比
app:layout_constraintWidth_default="percent"
或app:layout_constraintHeight_default="percent"
(**注意:**这在1.1-beta1和1.1-beta2中是必需的,但如果定义了percent属性,则在以下版本中不需要) - 然后将
layout_constraintWidth_percent
或layout_constraintHeight_percent
属性设置为0到1之间的值
3.11、Ratio比例
您还可以将窗口小部件的一个维度定义为另一个尺寸的比率。为此,您需要将至少一个约束尺寸设置为0dp
(即MATCH_CONSTRAINT
),并将该属性layout_constraintDimensionRatio
设置为给定比率。
[例]:指定高度为MATCH_CONSTRAINT
(0dip),设置宽高为1:1
<Button
android:id="@+id/buttonA"
android:layout_width="100dip"
android:layout_height="0dp"
android:text="AAAAAAAAAA"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
注意:控件需要包涵约束,才可以使用比例app:layout_constraintDimensionRatio
该比率可表示为:
- 浮点数值,表示宽度和高度之间的比率
app:layout_constraintDimensionRatio="1.0"
- “宽度:高度”(例如:1:1)形式的比率
app:layout_constraintDimensionRatio="1:1"
指定约束边(比率前添加字母W
(用于约束宽度)或H
(用于约束高度),用逗号分隔)
[例1]:控件A设置了宽度为100dip,高度设置了MATCH_CONSTRAINT
(0dp)
不指定约束边
不指定约束边默认算法宽:高=比率(2:1)
,因为指定宽为100dip。所以高=宽/比率(2/1)=50dip
<Button
android:id="@+id/buttonA"
android:layout_width="100dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定H
(用于约束高度)
指定android:layout_width="100dip"
、"H,2:1"
相反算法:宽:高=比率(2:1)
所以高=宽/比率(2/1)=50dip
<Button
android:id="@+id/buttonA"
android:layout_width="100dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="H,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定W
(用于约束宽度)
指定android:layout_width"100dip"
、"W,2:1"
相同算法:高:宽=比率(2:1)
所以高=宽*比率(2/1)=200dip
<Button
android:id="@+id/buttonA"
android:layout_width="100dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="W,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
[例2]:控件A设置了高度为100dip,宽度设置了MATCH_CONSTRAINT
(0dp)
不指定约束边
不指定约束边默认算法宽:高=比率(2:1)
,因为指定高为100dip。所以宽=高*比率(2/1)=200dip
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="100dip"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定H
(用于约束高度)
指定android:layout_height"100dip"
、"H,2:1"
相同算法:高:宽=比率(2:1)
所以宽=高/比率(2/1)=50dip
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="100dip"
app:layout_constraintDimensionRatio="H,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定W
(用于约束宽度)
指定android:layout_height"100dip"
、"W,2:1"
相反算法:宽:高=比率(2:1)
所以宽=高*比率(2/1)=200dip
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="100dip"
app:layout_constraintDimensionRatio="W,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
[例3]:控件A设置了高度、宽度都设置了MATCH_CONSTRAINT
(0dp)
不指定约束边
这里指定了app:layout_constraintLeft_toLeftOf="parent"
、app:layout_constraintRight_toRightOf="parent"
说明了宽度值固定,相当于指定了宽度
不指定约束边默认算法宽:高=比率(2:1)
,因为指定宽为屏幕宽度。所以高=宽/比率(2/1)=屏幕宽度一半
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定H
(用于约束高度)
指定屏幕宽度
、"H,2:1"
相反算法:宽:高=比率(2:1)
所以高=宽/比率(2/1)=屏幕宽度一半
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="H,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
指定W
(用于约束宽度)
指定屏幕宽度
、"W,2:1"
相同算法:高:宽=比率(2:1)
所以高=宽*比率(2/1)=屏幕宽度2倍
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="0dip"
app:layout_constraintDimensionRatio="W,2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
3.12、Chains链
链在单个轴(水平或垂直)上提供类似行的行为。另一个轴可以独立约束。
3.12.1、创建一个链
如果一组控件通过双向连接连接在一起,那么这组控件就被认为是一个链。下图显示了一个最小的链。
3.12.2、链头
链由链的第一个元素(链头)上的属性控制:
- 水平链链头:最左侧的控件
- 垂直链链头:最上方的控件
3.12.3、链中的边距
连接中设置的边距也会计算在内。在链展开的情况下,边距会从分配的空间中扣除。
3.12.4、链样式
当链的第一个元素设置了layout_constraintHorizontal_chainStyle
或layout_constraintVertical_chainStyle
属性,链样式将按照指定的方式改变(默认是CHAIN_SPREAD
)。
- CHAIN_SPREAD元素将展开(默认);
- 权重链在
CHAIN_SPREAD
模式下,如果一些控件设置了MATCH_CONSTRAINT
,这些控件将分担可用空间; - CHAIN_SPREAD_INSIDE元素展开,但链的端点不会展开;
- CHAIN_PACKED链中的元素将包裹在一起。子控件的水平或垂直方向的偏置
bias
属性会影响包裹中元素的位置。
3.12.5、权重链
链的作用是在可用空间内均匀的分布元素。如果一个或多个使用MATCH_CONSTRAINT
,它们将抢占可用空间(它们之间均分)。属性layout_constraintHorizontal_weight
和layout_constraintVertical_weight
可以控制使用MATCH_CONSTRAINT
的元素如何分配空间。例:一条链控制了两个使用MATCH_CONSTRAINT
的元素,第一个元素权重为2,第二个元素权重为1,那么第一个元素占用的空间是第二个元素的两倍。
[例1]: C控件40dip,A空件、B控件平分剩余空间:
使用layout_constraintHorizontal_weight
权重实现
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB" />
<Button
android:id="@+id/buttonB"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toLeftOf="@id/buttonC" />
<Button
android:id="@+id/buttonC"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
app:layout_constraintRight_toRightOf="parent" />
[例2]: A、B、C三个空间平分空间,使用app:layout_constraintHorizontal_chainStyle="spread"
默认属性
<Button
android:id="@+id/buttonA"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB" />
<Button
android:id="@+id/buttonB"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toLeftOf="@id/buttonC" />
<Button
android:id="@+id/buttonC"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
app:layout_constraintRight_toRightOf="parent" />
[例3]: A、B、C三个空间平分空间,首尾控件靠父布局边缘,使用app:layout_constraintHorizontal_chainStyle="spread_inside"
<Button
android:id="@+id/buttonA"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB" />
<Button
android:id="@+id/buttonB"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toLeftOf="@id/buttonC" />
<Button
android:id="@+id/buttonC"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
app:layout_constraintRight_toRightOf="parent" />
[例4]: A、B、C三个空间平分首尾空间,使用app:layout_constraintHorizontal_chainStyle="packed"
<Button
android:id="@+id/buttonA"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB" />
<Button
android:id="@+id/buttonB"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toLeftOf="@id/buttonC" />
<Button
android:id="@+id/buttonC"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
app:layout_constraintRight_toRightOf="parent" />
[例5]: A、B、C三个空间平分首尾空间,增加偏移属性偏移左方20%,使用app:layout_constraintHorizontal_bias="0.2"
、
app:layout_constraintHorizontal_chainStyle="packed"
<Button
android:id="@+id/buttonA"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/buttonB" />
<Button
android:id="@+id/buttonB"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/buttonA"
app:layout_constraintRight_toLeftOf="@id/buttonC" />
<Button
android:id="@+id/buttonC"
android:layout_width="40dip"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/buttonB"
app:layout_constraintRight_toRightOf="parent" />
3.13、Guideline
Guideline
是只能用在ConstraintLayout布局里面的一个工具类,用于辅助布局,类似为辅助线,可以设置android:orientation
属性来确定是横向的还是纵向的。
- 当设置为
vertical
的时候,Guideline
的宽度为0,高度是parent
也就是ConstraintLayout的高度 - 同样设置为
horizontal
的时候,高度为0,宽度是parent
的宽度
重要的是Guideline是不会显示到界面上的,默认是GONE的。
Guideline
还有三个重要的属性,每个Guideline
只能指定其中一个:
layout_constraintGuide_begin
,指定左侧或顶部的固定距离,如100dp,在距离左侧或者顶部100dp的位置会出现一条辅助线layout_constraintGuide_end
,指定右侧或底部的固定距离,如30dp,在距离右侧或底部30dp的位置会出现一条辅助线layout_constraintGuide_percent
,指定在父控件中的宽度或高度的百分比,如0.8,表示距离顶部或者左侧的80%的距离
[例1]: 控件A在屏幕的10%处,控件B在距离左边150dip处,控件C距离右边10dip处
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1" />
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toRightOf="@id/guideline1" />
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="150dip" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/guideline2" />
<android.support.constraint.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="10dip" />
<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintRight_toLeftOf="@id/guideline3" />
[例2]: 控件A占屏幕宽度的一半,可以用layout_constraintGuide_percent
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/guideline1" />
3.14、Group(1.1中添加)
Group 用于控制所引用的一组控件的可见性(Visibility),constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。
注意 多个Group 部件可以引用相同的控件,这时Group 在xml中的定义顺序将决定这个控件最终的可见性。
[例]:控制控件A、控件B同时显示和隐藏,使用android.support.constraint.Group
解决
<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="buttonA,buttonB" />
<Button
android:id="@+id/buttonA"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_marginTop="50dip"
android:text="B"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
3.15、Barrier(1.1中添加)
Barrier 使用多个控件作为参考,在这些控件中,选取在特定方向最边缘的的控件创建一条Guideline。
constraint_referenced_ids用来设置要参考的控件id,多个控件id间以逗号的形式隔开。
[例]:控件C始终在控件A、控件B右侧,使用android.support.constraint.Barrier
来管理控件A、控件B
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BBBBBBBBBBBBBBB"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/buttonA" />
<android.support.constraint.Barrier
android:id="@+id/barrier1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="buttonA,buttonB"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toEndOf="@+id/barrier1"
app:layout_constraintTop_toTopOf="parent" />
3.16、Placeholder(1.1中添加)
占位布局。他自己本身不会绘制任何内容,但他可以通过设置app:content=“id”,将id View的内容绘制到自己的位置上,而原id的 View就像gone了一样。 如下:
<Button
android:id="@+id/buttonA"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AAAAAAA" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BBBBBBBB"
app:layout_constraintLeft_toRightOf="@id/buttonA" />
<android.support.constraint.Placeholder
android:id="@+id/place"
android:layout_width="200dp"
android:layout_height="200dp"
app:content="@+id/buttonA"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
可以看到,原本A是位于B的右边并且顶部对齐的,但因为A被Placeholder引用,使A 相当于Gone了。而Placeholder的位置则显示了A的内容,并且大小也和A相符,Placeholder的大小设置并没有生效。 大概总结可以认为,Placeholder引用A后的效果是,原本位置的A gone,原本位置的Placeholder变为Placeholder的约束属性+A的内容属性。另外,Placeholder也支持使用代码setContentId动态的修改设置内容。
关于Placeholder的应用场景,网上其他人也都列出了一些例子:比如可以作为位置模板,引入后只需要写内容view;使用代码动态改变内容,结合TransitionManager可以做一些有趣的过度动画等。
四、案例
需求:要求产品类型紧跟产品名称后面,当产品名称过长使用“…”省略,不会影响产品类型展示,如下正常效果图. 可使用ConstraintLayout
实现,当文字过长时也可以正常展示(如下文字过长效果图)
正常效果:
文字过长效果:
实现代码如下:
<?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="match_parent"
android:padding="5dip">
<TextView
android:id="@+id/tv_demo_rate_value"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="1.31"
android:textColor="@android:color/holo_red_light"
android:textSize="20sp"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintWidth_max="wrap" />
<TextView
android:id="@+id/tv_demo_per_cent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dip"
android:text="%"
android:textColor="@android:color/holo_red_light"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="@id/tv_demo_rate_value"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toRightOf="@id/tv_demo_rate_value"
app:layout_constraintRight_toLeftOf="@id/gline_demo_v" />
<TextView
android:id="@+id/tv_demo_annual_rate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="年利率"
android:textSize="12sp"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toLeftOf="@id/tv_demo_rate_value"
app:layout_constraintRight_toLeftOf="@id/gline_demo_v"
app:layout_constraintTop_toBottomOf="@id/tv_demo_rate_value" />
<android.support.constraint.Guideline
android:id="@+id/gline_demo_v"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3" />
<TextView
android:id="@+id/tv_demo_product_name"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="工资理财118号"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@id/gline_demo_v"
app:layout_constraintWidth_max="wrap" />
<TextView
android:id="@+id/tv_demo_product_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="5000元申购"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="@id/tv_demo_annual_rate"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toRightOf="@id/gline_demo_v"
app:layout_constraintRight_toLeftOf="@id/iv_demo_product_back"
app:layout_constraintTop_toBottomOf="@id/tv_demo_product_name"
app:layout_constraintVertical_bias="1" />
<TextView
android:id="@+id/tv_demo_product_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_light"
android:padding="1dip"
android:singleLine="true"
android:text="热销产品"
android:textColor="@android:color/white"
android:textSize="14sp"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintLeft_toRightOf="@id/tv_demo_product_name"
app:layout_constraintRight_toLeftOf="@id/iv_demo_product_back" />
<android.support.constraint.Barrier
android:id="@+id/barrier_demo_v"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="tv_demo_annual_rate,tv_demo_product_desc" />
<ImageView
android:id="@+id/iv_demo_product_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_media_play"
app:layout_constraintBottom_toTopOf="@id/barrier_demo_v"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>