概述
约束布局
ConstraintLayout
是谷歌2016年I/O大会发布的新型的layout布局,旨在最大化的减少复杂布局的层级嵌套,实现布局的扁平化,提升页面的渲染速度。
在AS 2.2的版本以上,默认为App
依赖了最新的约束布局库,在创建布局文件时也会默认为约束布局,这从侧面反映出来官方推荐开发者使用约束布局。
- 与传统布局相比的优势
约束布局的拖拽操作
约束布局在AS2.2以上版本中支持可视化拖拽操作,自己实际操作后对这种拖拽方式使用起来很不习惯,而且手动拖拽经常会导致某些参数调整不准。所以本文不讲拖拽,如果有需要,请看下面的链接。
同样UI用常规布局和约束布局前后对比
常规布局实现
为节省空间,省去部分细节代码,主要看布局结构
可以看到这是比较复杂的布局,所以再一开始写的时候这里最外层用的布局也是相对布局,但写下来依然嵌套最深层需要5层布局。
约束布局进行改造
可以看到约束布局实现整个效果没有任何嵌套,所有需要嵌套的View全部扁平化处理了,大大提高了布局渲染速度。
约束布局的具体使用
添加依赖
1
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
相对位置属性
这个与相对布局很相似,是以某个View布局为约束来控制自己所在的位置的。官方提供了以下属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//这些属性见名知义,非常好理解
//当前view的左侧位置与目标view左侧位置对齐
layout_constraintLeft_toLeftOf
//当前view的左侧位置与目标view右侧位置对齐
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例子:
这里最上边有一个分割线,下面是一整个横向布局的View
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<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:background="@color/white">
//最顶上的分割线 view的顶部的父布局的顶部对齐
<View
android:id="@+id/gap"
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@drawable/m_home_bbs_space_bar_gray_bottom_half"
app:layout_constraintTop_toTopOf="parent"/>
//左上角的推荐的icon在分割线下面 所以是该View的顶部在分割线底部的下面
<ImageView
android:id="@+id/id_community_item_recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/m_home_bbs_waterfall_recommend"
app:layout_constraintTop_toBottomOf="@id/gap"/>
//用户头像是在分割线下面,同时据布局的左侧呦12dp的距离
//所以是左侧与父布局的左侧对齐+marginLeft, 顶部在分割线底部的下面
<ImageView
android:id="@+id/item_community_head"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginLeft="12dp"
android:layout_marginTop="12dp"
android:scaleType="fitXY"
android:src="@drawable/m_home_bbs_default_head"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/gap"/>
//用户头像右下角的身份图标
//所以是底部与头像的底部对齐,右侧与头像的右侧对齐
<ImageView
android:id="@+id/item_community_auth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:scaleType="fitXY"
android:src="@drawable/m_home_icon_v"
app:layout_constraintBottom_toBottomOf="@id/item_community_head"
app:layout_constraintRight_toRightOf="@id/item_community_head"/>
//头像右侧又处于上方的名字
//所以是左侧在头像的右侧,顶部与头像的顶部对齐
<TextView
android:id="@+id/item_community_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/padding_small"
android:text="12312312"
android:textColor="#28354C"
android:textSize="14sp"
app:layout_constraintLeft_toRightOf="@id/item_community_head"
app:layout_constraintTop_toTopOf="@id/item_community_head"/>
//头像右侧又处于下方的提示
//所以是左侧在头像的右侧,底部与头像底部对齐
<TextView
android:id="@+id/item_community_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/padding_small"
android:text="12312312"
android:textColor="#a6a8b6"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/item_community_head"
app:layout_constraintLeft_toRightOf="@id/item_community_head"/>
//vip图标在名字的右侧,同时底部又对齐
<ImageView
android:id="@+id/item_community_svip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/padding_small"
android:layout_marginTop="1dp"
android:src="@drawable/m_home_bbs_svip"
android:visibility="visible"
app:layout_constraintLeft_toRightOf="@id/item_community_name"
app:layout_constraintTop_toTopOf="@id/item_community_head"/>
//关注按钮在父布局的右侧 同时是在头像一横栏的中间部位
//所以右侧与父布局右侧对齐 顶部与头像顶部对齐 底部与头像底部对齐
<ImageView
android:id="@+id/community_item_follow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:src="@drawable/m_home_bbs_focus"
app:layout_constraintBottom_toBottomOf="@id/item_community_head"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/item_community_head"/>
</android.support.constraint.ConstraintLayout>一般实现像上面关注按钮位于头像中间的效果,传统布局都会在外面套一层布局,然后设置居中,可以看到约束布局只要顶部和底部与头像对齐就可以了。为什么会这样呢?看下一个特性
Bias偏重
1
2
3
4//横向约束的偏重 默认是0.5
layout_constraintHorizontal_bias
//纵向约束的偏重,默认是0.5
layout_constraintVertical_bias在约束布局中,当控件宽度为warp_content、固定值的时候,为控件添加的其实都是约束”Constraint”,这个约束就好像有个橡皮筋一样,但是并不会改变控件的尺寸。上面的关注按钮之所以会居中,其实是因为上下以头像为约束,同时纵向约束的权重默认是0.5所以自然会居中
再看一个例子
像这样悬浮的按钮,传统布局外面用帧布局或者相对布局实现,并且传统布局必须要计算距离底部的dp值用来适配布局,而不能准确实现距离底部的百分比。那约束布局就可以使用这个权重属性来完美实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<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">
//可以看到这里设置纵向约束比为0.9表明距底部10%
<ImageButton
android:id="@+id/community_home_edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/m_home_transparent"
android:src="@drawable/m_home_button_float_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.9"/>
</android.support.constraint.ConstraintLayout>0dp(MATCH_CONSTRAINT)
上面的属性已经完全可以替代相对布局了,下面说一下不同点,同样地,看个例子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<RelativeLayout
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/id_btn01"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Btn01"/>
<Button
android:id="@+id/id_btn02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/id_btn01"
android:text="Btn02"/>
</RelativeLayout>如果用约束布局地话,我们把
layout_toRightOf="@id/id_btn01",layout_alignParentRight="true"
分别替换为app:layout_constraintLeft_toRightOf="@id/id_btn01",app:layout_constraintRight_toRightOf="parent"
但是效果却不一样了原因:就是上面权重解释的那样。
如果需要实现上面的相对布局的效果,只需要给btn02的宽度设置为0dp就解决了。
0dp在约束布局中的意思就是MATCH_CONSTRAINT,意思就是让约束控制这个宽度。1
2
3//当控件设置了0dp,还可以指定控件的宽度或者高度占父控件的百分比 值在0-1之间
layout_constrainWidth_percent
layout_constrainHeight_percentlayout_constraintDimensionRatio宽高比
1
2
3//实现控件的宽高比 宽度或者高度必须有一个是0dp
//这里的值可以为数字a:数字b 默认是宽高比 如果想指定高比宽 数字a前面H,
layout_constraintDimensionRatio 例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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">
//layout_constraintWidth_percent=0.5 意思是宽度为父布局的一半,前提是宽度为0dp
//layout_constraintDimensionRatio="4:3" 宽高比4:3
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="4:3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintWidth_percent="0.5"/>
</android.support.constraint.ConstraintLayout>1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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">
//高度固定,宽度0dp,宽高比1:2
<Button
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintDimensionRatio="h,2:1"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>chains与weight
先看张常见的布局图
像这样的效果,传统布局的方式都是用线性布局的weight属性实现。而经过前面的介绍,可以发现约束布局已经完全可以替代相对布局了,下面看看上面的效果在约束布局中如何实现。
chains很像线性布局中的weight属性,但是更为灵活。Chains必须有两个View组成,这两个View相互约束,Chains中的第一个控件叫做链头chain head,Chain Style的样式主要由链头来控制。看张官方的chain style图
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<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">
//layout_constraintRight_toLeftOf="@id/tv2"
//button1在button2的左边
//layout_constraintHorizontal_chainStyle="spread" 链子的样式为平铺,相当于线性布局的weight
<Button
android:id="@+id/tv1"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#f67"
android:gravity="center"
android:text="微医"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintRight_toLeftOf="@id/tv2"/>
//app:layout_constraintLeft_toRightOf="@id/tv1"
//button2在button1的右边 这里再声明一遍在Button1的右边,是因为组成链子需要两两约束
//button2在button3的左边
<Button
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#A67"
android:gravity="center"
android:text="问诊"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintRight_toLeftOf="@id/tv3"/>
//button3在Button2的右边
//3个button两两形成约束,组成一个chain,链子的样式由链头控制
//
<Button
android:id="@+id/tv3"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#767"
android:gravity="center"
android:text="社区"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv2"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>chain style除了默认的spread,还有其他两种packed、spread_inside
这两种效果,分别看下:spread + 宽度非0
packed + 宽度非0
spread_inside + 宽度非0
更多的效果看下官方的图
Guideline基线
还是先来张图
上面我们是通过bais来实现的,约束布局其实还可以通过基线来实现。
Guideline主要用于辅助布局,即类似为辅助线,横向的、纵向的。并且它是不会显示到界面上的。
Guideline有以下几个属性1
2
3
4
5
6
7
8//基线的方向 分为横向和纵向
orientation
//基线占ConstraintLayout的宽或高的百分比
layout_constraintGuide_percent
//基线距离ConstraintLayout的左侧或者顶部的距离
layout_constraintGuide_begin
//距离ConstraintLayout的右侧或者底部的距离
layout_constraintGuide_end例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<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">
//声明一个纵向的基线,左侧距离父布局80%的宽度
<android.support.constraint.Guideline
android:id="@+id/guide1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.8"/>
//声明一个横向的基线,顶部距离父布局80%的宽度
<android.support.constraint.Guideline
android:id="@+id/guide2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8"/>
//位于纵向基线的右侧 横向基线的下侧
<ImageButton
android:id="@+id/community_home_edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/m_home_transparent"
android:src="@drawable/m_home_button_float_background"
app:layout_constraintLeft_toRightOf="@id/guide1"
app:layout_constraintTop_toBottomOf="@id/guide2"/>
</android.support.constraint.ConstraintLayout>效果图
Barrier边界
Barrier边界也是一个用来辅助布局的控件,它的作用是限制其所引用的一组View边界
这里看一个网上的例子。
上面的布局是左侧有两个textview,上部的为tv1,下部的为tv2),tv1和tv2的宽度不定,而tv3要处于他们俩的右侧。但是究竟以谁为准呢?不好确定。图中的tv3是在tv1的右边。那么此时如果tv2的内容过长,就会出现tv2的文字盖在了tv3的上面。
这个问题可以通过Barrier来解决。
1
2
3
4
5
6
7
8//设置 Barrier 所创建的位置 值有left、start、right、end、top、 bottom
//给约束目标指定对齐的方向
barrierDirection
//指定Barrier引用的view的ID,以逗号隔开,无需加 @id
constraint_referenced_ids
//默认为true,,即当 Barrier 引用的控件被 GONE 掉时,则 Barrier默认的创建行为
//是在已 GONE 掉控件的已解析位置上进行创建。如果设置为 false,则不会将 GONE 掉的控件考虑在内。
barrierAllowsGoneWidgets解决上述问题的代码:
1 |
|
Group控件组
在日常的需求开发中,经常会碰到要对某些View同时进行显示或者隐藏。传统的做法要么是获取这些View的引用,逐个进行设置,要么是外面套层ViewGroup统一实现。但后面这种实现方式有很大的局限性,第一需要隐藏的View可以统一外面包层布局,第二增加了布局的复杂性,影响性能。这种问题,约束布局就能很好的解决。
Group用来控制一组控件的可见性。
1
2//指定所引用控件的 id。
constraint_referenced_ids如果有多个 Group,是可以同时指定相同的控件的,最终是以 XML 中最后声明的 Group 为准。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<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">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="123123123"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿"
android:textColor="@color/circleColor"
android:textSize="15sp"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv1"/>
//引用tv1,tv2,统一隐藏
<android.support.constraint.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv1,tv2"/>
</android.support.constraint.ConstraintLayout>Placeholder占位符
Placeholder (占位符)用于和一个视图关联起来,通过 setContentId() 方法将占位符转换为指定的视图,即视图将在占位符所在位置上显示,如果此时布局中已包含该视图,则视图将从原有位置消失。除此之外,还可以通过 setEmptyVisibility() 方法设置当视图不存在时占位符的可见性。
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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">
//设置一个点击事件
<ImageView
android:id="@+id/logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gh_cm_wy_logo"
android:onClick="logoClick"/>
//创建一个占位符,用来替换logo
<android.support.constraint.Placeholder
android:id="@+id/placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>点击图片前,logo在屏幕的左上角效果图
1
2
3
4public void logoClick(View view) {
Placeholder placeholder = findViewById(R.id.placeholder);
placeholder.setContentId(R.id.logo);
}点击图片后,会发现logo处于屏幕中间了。图就不贴了。
另外setContentId也可以在XML中直接给placeholder设置。1
2//直接xml设置,相当于提前触发了点击事件
app:content="@id/logo"点击图片后,会发现logo处于屏幕中间了。图就不贴了。
另外setContentId也可以在XML中直接给placeholder设置。1
2//直接xml设置,相当于提前触发了点击事件
app:content="@id/logo"goneMargin隐藏边距
这个属性比较有意思,是当一个View与另一个View绑定后,另一个View的属性设置为了Gone,则该属性会生效。
当设置了goneMargin属性时候,约束的控件如果不是GONE的时候,则不会生效;
当goneMargin属性和margin属性同时存在的时候,margin属性不会生效。1
2
3
4
5
6
7
8//隐藏开始边距 同left
layout_goneMarginStart
//隐藏结束边距 同right
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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"
android:layout_height="wrap_content"
android:text="button3"
android:visibility="visible"/>
//Button2在button1的右边,button2以button1为约束,button2设置了goneMarginLeft
//当Button1可见的时候,android:layout_marginLeft="40dp"会生效,而GoneMargin不会生效
//当Button1隐藏的时候,正好相反,两者不会同时生效
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button4"
app:layout_constraintLeft_toRightOf="@id/btn1"
app:layout_goneMarginLeft="20dp"
android:layout_marginLeft="100dp"/>
</android.support.constraint.ConstraintLayout>Button1可见时
Button1隐藏时Visibility behavior可见性行为
当一个控件设置为GONE的时候,在布局计算的时候仍会加进去。在布局过程中,将被解析成一个点,所有的margin也将为0,但是对于其他控件的约束仍然存在。
还是看上面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<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"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="button1"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="100dp"
android:text="button2"
app:layout_constraintLeft_toRightOf="@id/btn1"/>
</android.support.constraint.ConstraintLayout>button1距屏幕左侧10dp,button2在button1右边100dp。如果button1隐藏,button2的位置会往左偏移,变成距离屏幕左侧100dp。如何保持button2的位置呢?
button2就必须设置一个goneMarginLeft= button1.with + button1.marginLeft + button2.marginLeft
Enforcing constraints强制约束
1
2
3
4
5
6
7
8//设置控件的最大宽度
layout_constraintWidth_max
//设置控件的最大高度
layout_constraintHeight_max
//设置的最大高度是否生效
layout_constrainedHeight
//设置的最大宽度是否生效
layout_constrainedWidth在1.1版本之前,对控件设置了warp_content,如果再设置控件的最大宽度、最大高度这样的约束是无效的。再1.1版本,可以添加强制约束,保证其生效。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<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">
//button1未设置强制约束,运行后会发现设置的最大宽度和最大高度是无效的
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="无效max"
app:layout_constraintHeight_max="40dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintWidth_max="50dp"/>
//button2设置了强制约束,生效。
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="有效max"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintHeight_max="50dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_max="50dp"/>
</android.support.constraint.ConstraintLayout>Circular Positioning圆形定位
约束布局除了可以使用相对布局类似的属性定位,还提供了额外的圆形定位。
1
2
3
4
5
6//参照View的ID
app:layout_constraintCircle
//对齐的角度(顺时针方向,0~360度)
app:layout_constraintCircleAngle
//与参照View之间的距离
app:layout_constraintCircleRadius例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<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">
//button1是参照View,处于屏幕中间
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="参照View"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
//button2参照button1,位于button1135度,长度未100dp的地方
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="定位View"
app:layout_constraintCircle="@id/btn1"
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="100dp"/>
</android.support.constraint.ConstraintLayout>
参考链接
Android ConstraintLayout 最新使用小结
Android 约束布局(ConstraintLayout)1.1.0 版详解
约束布局(ConstraintLayout)1.1.2 版本的新特性
Android ConstraintLayout的使用
ConstraintLayout 完全解析 快来优化你的布局吧
Android 约束布局(ConstraintLayout)详解