ConstraintLayout⽤法
当前描述是基于constraint-layout:1.1.2。
⼀、前⾔
在以前,android是使⽤布局如LinearLayout、RelativeLayout等来构建页⾯,但这些布局使⽤起来很⿇烦,并且经常需要⼀层⼀层嵌套,写
⼀个简单的页⾯就需要费很⼤的劲。所以在16年I/O⼤会上,google发布了全新的布局-ConstraintLayout,其他布局和ConstraintLayout⽐起
来,根本就没有存在的必要了...
ConstraintLayout具有以下优势:
1.较⾼的性能优势。
布局嵌套层次越⾼,性能开销越⼤。⽽使⽤ConstraintLayout,经常就⼀层嵌套就搞定了,所以其性能要好很多。
2.完美的屏幕适配
ConstraintLayout的⼤⼩、距离都可以使⽤⽐例来设置,所以其适配性更好。
3.书写简单
4.可视化编辑。
ConstraintLayout也有⼗分⽅便完善的可视化编辑器,不⽤写xml也基本上能实现⼤部分功能。但个⼈还是⽐较喜欢写xml,所以本篇⽂
章主要介绍如何使⽤代码控制。如果想看如何使⽤可视化编辑器,可以参考郭霖⼤神的
1引⼊:api'aint:constraint-layout:1.1.2'
⼆、ConstraintLayout
1.定位位置
确定位置的属性提供了下⾯13个属性,其实本质上都是⼀样的,看名字应该基本上都知道怎么⽤了(就是哪⼀条边和哪⼀条边对齐)
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_constraintBaline_toBalineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
来看个例⼦:
实现上述UI的相关代码如下:
1
2...>
3
4
5android:id="@+id/a"
6....
7app:layout_constraintLeft_toLeftOf="parent"
8app:layout_constraintTop_toTopOf="parent"
9android:text="A"/>
10
11
12android:id="@+id/b"
13....
14app:layout_constraintLeft_toRightOf="@id/a"
15app:layout_constraintTop_toTopOf="@id/a"
16android:text="B"/>
17
18
19android:id="@+id/c"
20....
21app:layout_constraintLeft_toLeftOf="@id/a"
22app:layout_constraintTop_toBottomOf="@id/a"
23android:text="C"/>
24
25
26android:id="@+id/d"
27....
28app:layout_constraintLeft_toRightOf="@id/a"
29app:layout_constraintTop_toTopOf="@id/c"
30android:text="D"/>
31
从中可以看到,
layout_constraint*属性的值可以是某个id或者parent(⽗布局)
B要位于A的右边,则使⽤app:layout_constraintLeft_toRightOf="@id/a",C位于A的下边,则使⽤app:layout_constraintTop_toBottomOf="@id/a"
对于⼀个View的边界界定,官⽅给了下⾯这张图:
设置margin还是继续⽤以前的属性layout_margin*。
不过需要注意,要使margin⽣效,必须具有对应⽅向的layout_constraint*,否则margin不⽣效.
3.关于viewgone
假如现在有如下布局:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6android:id="@+id/a"
7...
8android:layout_marginLeft="100dp"
9android:layout_marginTop="20dp"
10app:layout_constraintLeft_toLeftOf="parent"
11app:layout_constraintTop_toTopOf="parent"/>
12
13
14android:id="@+id/b"
15...
16android:layout_marginLeft="20dp"
17android:layout_marginTop="20dp"
18app:layout_constraintLeft_toRightOf="@id/a"
19app:layout_constraintTop_toTopOf="@id/a"
20/>
21
22
23android:id="@+id/c"
24....
25android:layout_marginLeft="20dp"
26android:layout_marginTop="20dp"
27app:layout_constraintLeft_toRightOf="@id/b"
28app:layout_constraintTop_toTopOf="@id/b"/>
29
考虑⼀个问题,如果B动态设为gone了,C会怎么显⽰呢?
真实情况如下:
为什么会这样显⽰呢?看他的蓝图应该会好理解些:
可以看出,b设为gone之后,他的宽、⾼、margin都失效了,变为⼀个点了,但它的constrain还⽣效,位于指定的位置。c还是可以继续以
他为锚点。
那么如何解决关于Viewgone引起的⾮预期的布局变化呢?
1.如果可以,尽量使⽤invisible
2.尽量其他view的布局不依赖会gone的view
也提供了属性layout_goneMargin*="xdp",意思是⽐如当constrainleft的锚点gone时,layout_goneMarginLeft将⽣效。但因为这个只
能设置固定的距离,个⼈感觉灵活性不是很⾼。
4.居中及bias
⼀个view如何设置为居中呢?如果查找属性,会发现并没有如RelativeLayout类似的layout_centerVertical属性,那如何设置居中
呢?constraint的思想很巧妙。
根据第⼀节的知识,⼤家知道如果设置app:layout_constraintLeft_toLeftOf="parent",则view会贴着⽗view的左边,设
置app:layout_constraintRight_toRightOf="parent"则会贴着右边,那如果两个都设置,效果会怎样呢?
如图,两个都设置,view则会居中。
⾄此可以看出,对constraint的理解其实可以看成是像两个弹簧⼀样,如果只在左边加⼀个弹簧,右边没有,那左边的势必会把view拉到左
边去,如果在右边也加⼀根弹簧,两个弹簧⼒相互平衡,则view就居中了。
上⾯是view居中,如果我想让view向左偏⼀些,或者位于1/3处该怎么处理?其实也是⼀样的,想象⼀下,如果左边的弹簧⼒⼤⼀些,view
不是就⾃然往左偏了嘛。如何使⼒⼤⼀些呢?使⽤如下属性
layout_constraintHorizontal_bias
layout_constraintVertical_bias
bias即偏移量,他们的取值范围从0~1,0即挨着左边,1是挨着右边,所以要使处于1/3处,可以设置如下属
性app:layout_constraintHorizontal_bias="0.33",效果图如下:
的尺⼨
设置view的⼤⼩除了传统的wrap_content、指定尺⼨、match_parent(虽然官⽅不推荐使⽤match_parent)外,还可以设置为0dp(官⽅取名
叫MATCH_CONSTRAINT),0dp在constraint可不是指⼤⼩是0dp,⽽是有特殊含义的。他的作⽤会随着不同的设置有不同的含义:
_constraintWidth_default
layout_constraintWidth_default有三个取值,作⽤如下:
spread,默认值,意思是占⽤所有的符合约束的空间
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6android:id="@+id/a"
7android:layout_width="0dp"
8...
9android:layout_marginLeft="20dp"
10android:layout_marginRight="20dp"
11app:layout_constraintRight_toRightOf="parent"
12app:layout_constraintLeft_toLeftOf="parent"/>
13
14
可以看到layout_width为0dp,实际的效果则是宽度和约束⼀样,左右两边的留⽩是margin的效果。
percent,意思是按照⽗布局的百分⽐设置,需要layout_constraintWidth_percent设置百分⽐例
1<?xmlversion="1.0"encoding="utf-8"?>
2
3
4
5android:layout_width="300dp"
6android:layout_height="400dp"
7app:layout_constraintHorizontal_bias="0.3"
8>
9
10
11android:id="@+id/a"
12android:layout_width="0dp"
13...
14app:layout_constraintRight_toRightOf="parent"
15app:layout_constraintWidth_default="percent"
16app:layout_constraintWidth_percent="0.4"/>
17
18
19
A的宽度设为0.4,则其宽度为⽗布局的0.4倍。另外,设置了layout_constraintWidth_percent属性,可以不⽤指定
layout_constraintWidth_default,他会⾃动设置为percent
wrap,意思匹配内容⼤⼩但不超过约束限制,注意和直接指定宽度为wrap_content的区别就是不超过约束限制,如下:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6
7android:id="@+id/a"
8...
9app:layout_constraintLeft_toLeftOf="parent"/>
10
11android:id="@+id/c"
12...
13app:layout_constraintRight_toRightOf="parent"/>
14
15
16android:id="@+id/b"
17android:layout_width="0dp"
18...
19app:layout_constraintWidth_default="wrap"
20app:layout_constraintLeft_toRightOf="@id/a"
21app:layout_constraintRight_toLeftOf="@id/c"/>
22
23
24android:id="@+id/d"
25android:layout_width="wrap_content"
26...
27app:layout_constraintTop_toBottomOf="@id/b"
28app:layout_constraintLeft_toRightOf="@id/a"
29app:layout_constraintRight_toLeftOf="@id/c"/>
30
31
可以看到虽然⽂字很长,但第⼀⾏的绿⾊button宽度达到约束时,就不在增加,⽽第⼆⾏的button显⽰了完整的内容,超过约束的限制。
在1.1上对于wrap_content会超过约束限制,⾕歌⼜新增了如下属性
app:layout_constrainedWidth=”true|fal”
app:layout_constrainedHeight=”true|fal”
设置为true也可以限制内容不超过约束(这样感觉layout_constraintWidth_default这个属性已经没什么⽤了)
layout_constraintDimensionRatio,即宽和⾼成⼀定的⽐例,其值可以是"width:height"的形式,也可以是width/height的值。该属性⽣效的前
提:宽和⾼其中有⼀项为0dp,有constraint。下⾯按照有⼏个0dp来分别介绍下:
如果只有⼀项为0dp,则该项值按照⽐例计算出来。⽐如⾼为20dp,宽为0dp,radio为"2:1",则最终宽为40dp
如果两项都为0dp,则尺⼨会设置为满⾜约束的最⼤值并保持⽐例。因为这是系统计算的,有的时候不是我们想要的,我们也可以通过
在前⾯加H、W来指定是哪⼀个边需要计算。例如"H,2:1",则是指宽度匹配约束,⾼度是宽度的1/2
有如下属性可以设置其的最⼤最⼩值,含义如字⾯值⼀样:
layout_constraintWidth_min
layout_constraintWidth_max
layout_constraintHeight_max
layout_constraintHeight_min
该属性在下⾯讲解
6.链
如图,在⼀个⽔平或者竖直⽅向上,⼀排view两两互相约束,即为链
链的第⼀个元素称为链头,可以通过设置layout_constraintHorizontal_chainStyle来控制链的分布形式
spread
默认模式,分布样式如上图
spread_inside
如图,和spread的区别是没算两端的约束
链的第⼀个元素称为链头,可以通过设置layout_constraintHorizontal_chainStyle来控制链的分布形式
spread
默认模式,分布样式如上图
spread_inside
如图,和spread的区别是没算两端的约束
packed
所有元素挤在中间,也可以配合使⽤bias来改变位置偏移
可以看出,链与LinearLayout效果⼤致⼀样。和LinearLayout⼀样,链也可以使⽤layout_constraintHorizontal_weight,来分割剩余空间。但⼜和
android:layout_weight不太⼀样,不⼀样的地⽅如下:
layout_weight,不管当前view的⼤⼩设的是多⼤,都会继续占据剩余空间
layout_constraintHorizontal_weight,这个只对0dp并且layout_constraintWidth_default为spread的view⽣效,使其⼤⼩按⽐例分割剩
余空间,对于已经设定⼤⼩的view不⽣效
如下⾯的⽰例:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6...
7android:orientation="horizontal">
8
9android:layout_width="10dp"
10android:layout_height="50dp"
11android:layout_weight="1"
12.../>
13
14android:layout_width="wrap_content"
15android:layout_height="50dp"
16android:layout_weight="1"
17.../>
18
19android:layout_width="0dp"
20android:layout_height="50dp"
21android:layout_weight="1"
22.../>
23
24
25
26....>
27
28
29android:id="@+id/a"
30android:layout_width="10dp"
31android:layout_height="50dp"
32....
33app:layout_constraintHorizontal_weight="1"
34app:layout_constraintLeft_toLeftOf="parent"
35app:layout_constraintRight_toLeftOf="@id/b"/>
36
37android:id="@+id/b"
38android:layout_width="wrap_content"
39android:layout_height="50dp"
40....
41app:layout_constraintHorizontal_weight="1"
42app:layout_constraintLeft_toRightOf="@id/a"
43app:layout_constraintRight_toLeftOf="@id/c"/>
44
45
46android:id="@+id/c"
47android:layout_width="0dp"
48android:layout_height="50dp"
49...
50app:layout_constraintHorizontal_weight="1"
51app:layout_constraintLeft_toRightOf="@id/b"
52app:layout_constraintRight_toRightOf="parent"/>
53
54/>
55
56
57
可以看出,LinearLayout和ConstraintLayout虽然三个⼦view的layout_width值是⼀样的,weight也都设置了1,但效果完全不⼀样
7.圆形布局
ConstraintLayout还提供了⼀种⽐较炫酷的圆形布局,这是以往的布局所做不到的。涉及到的属性也很简单,就下⾯三个:
layout_constraintCircle:圆⼼,值是某个view的id
layout_constraintCircleRadius:半径
layout_constraintCircleAngle:⾓度,值是从0-360,0是指整上⽅
⽰例如下:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6android:id="@+id/a"
7...
8/>
9
10
11android:id="@+id/b"
12...
13app:layout_constraintCircle="@id/a"
14app:layout_constraintCircleAngle="300"
15app:layout_constraintCircleRadius="100dp"/>
16
17
18android:id="@+id/c"
19...
20app:layout_constraintCircle="@id/a"
21app:layout_constraintCircleAngle="45"
22app:layout_constraintCircleRadius="200dp"/>
23/>
24
三、辅助组件
除了ConstraintLayout⾃⾝属性之外,⾕歌还提供了很多辅助布局(只是在布局中起辅助作⽤,并不会在界⾯真正显⽰),来
使ConstraintLayout的功能更加强⼤。下⾯,我们就⼀⼀来了解下这些布局
ine
即参考线的意思,有⽔平参考线和竖直参考线两种。他的作⽤就像是⼀个虚拟的参考线,只是⽤来⽅便其他View以他为锚点来布局。
如上⼀篇所了解到的,ConstraintLayout的定位原则就是⼀个View参考其他View的相对布局,如果有的时候当前布局没有合适的参考
View,⽽建⼀个专门⽤于定位的View⼜会太重,这种情况正是GuideLine的⽤武之地。
例如:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6android:id="@+id/guideline"
7...
8android:orientation="vertical"
9app:layout_constraintGuide_percent="0.33"/>
10
11
12android:id="@+id/guideline2"
13...
14android:orientation="horizontal"
15app:layout_constraintGuide_begin="130dp"/>
16
17
18...
19app:layout_constraintLeft_toLeftOf="@id/guideline"
20app:layout_constraintTop_toTopOf="@id/guideline2"/>
21
22
23
可以看到我分别添加了⼀个⽔平参考线和竖直参考线,之后的Button的布局就参考与这两个参考线,⽽在布局中并不会显⽰。
Guideline的⼤部分的属性如layout_width都是不会⽣效的,⽽他的位置的确定是由下⾯三个属性之⼀来确定的:
layout_constraintGuide_begin:距离⽗布局的左边或者上边多⼤距离
layout_constraintGuide_end:距离⽗布局的右边或者下边多⼤距离
layout_constraintGuide_percent:百分⽐,0~1,距离⽗布局的左边或者上边占⽗布局的⽐例
Group是⼀个可以同时控制多个view可见性的虚拟View。
例如:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5<
6...
7android:visibility="invisible"
8app:constraint_referenced_ids="a,c"/>
9
10<
11...
12android:visibility="visible"
13app:constraint_referenced_ids="b,d"/>
14
15
16android:id="@+id/a"
17.../>
18
19
20android:id="@+id/b"
21.../>
22
23
24android:id="@+id/c"
25.../>
26
27
28android:id="@+id/d"
29.../>
30
可以看到,第⼀个Group通过app:constraint_referenced_ids指定了a、c两个控件,这样当该Group可见性为invisible时,a、c的可见性都会变为
invisible,为gone则都为gone。所以Group很适合处理有⽹⽆⽹之类的场景,不再需要像之前那样⼀个⼀个view控制可见性,通过Group就
可以统⼀处理了。
Group有⼀些注意事项:
xml中,可见性配置的优先级:Group优先于View,下层Group优先于上层。
Group只可以引⽤当前ConstraintLayout下的View,⼦Layout下的View不可以。
app:constraint_referenced_ids⾥直接写的是id的字符串,初始化后会通过getIdentifier来反射查找叫该名字的id。所以如果你的项⽬⽤了类似
AndResGuard的混淆id名字的功能,切记不要混淆app:constraint_referenced_ids⾥的id,否则在relea版本就会因找不到该id⽽失效。或
者也可以通过代码tReferencedIds来设置id。
older
占位布局。他⾃⼰本⾝不会绘制任何内容,但他可以通过设置app:content="id",将idView的内容绘制到⾃⼰的位置上,⽽原id的View就像
gone了⼀样。
如下:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5android:id="@+id/a"
6android:layout_width="50dp"
7android:layout_height="50dp"
8android:layout_marginLeft="30dp"
9...
10app:layout_constraintLeft_toLeftOf="parent"
11app:layout_constraintTop_toTopOf="parent"/>
12
13
14android:id="@+id/b"
15android:layout_width="50dp"
16android:layout_height="50dp"
17android:layout_marginLeft="20dp"
18...
19app:layout_constraintLeft_toRightOf="@+id/a"
20app:layout_constraintTop_toTopOf="@+id/a"/>
21
22
23android:id="@+id/place"
24android:layout_width="200dp"
25android:layout_height="200dp"
26app:content="@+id/a"
27app:layout_constraintBottom_toBottomOf="parent"
28app:layout_constraintLeft_toLeftOf="parent"/>
29
30
31...
32app:layout_constraintBottom_toBottomOf="@+id/place"
33app:layout_constraintLeft_toRightOf="@+id/place"/>
34
效果如图:
可以看到,原本B是位于A的右边并且顶部对齐的,但因为A被Placeholder引⽤,使A相当于Gone了。⽽Placeholder的位置则显⽰了A的内
容,并且⼤⼩也和A相符,Placeholder的⼤⼩设置并没有⽣效。
⼤概总结可以认为,Placeholder引⽤A后的效果是,原本位置的Agone,原本位置的Placeholder变为Placeholder的约束属性+A的内容属
性。另外,Placeholder也⽀持使⽤代码tContentId动态的修改设置内容。
关于Placeholder的应⽤场景,⽹上其他⼈也都列出了⼀些例⼦:⽐如可以作为位置模板,引⼊后只需要写内容view;使⽤代码动态改变内
容,结合TransitionManager可以做⼀些有趣的过度动画等。
r
屏障,⼀个虚拟View。他主要解决下⾯遇到的问题:
如上图布局,两个TextView,⼀个button位于他们的右边。现在button设置的是在下⾯TextView的右边。假设有时候上⾯的TextView⽂本变
长了,则布局会变为下⾯这个样⼦:
上⾯的TextView和Button重叠了。这时该怎么解决这个问题呢?Button只能设置⼀个View作为锚点,设置了上⾯就顾不了下⾯了。。。
所以就诞⽣了Barrier,他可以设置N个View作为锚点,使⽤⽅式如下:
1
2android:id="@+id/barrier"
3android:layout_width="wrap_content"
4android:layout_height="wrap_content"
5app:barrierDirection="end"//end,left,right,top,bottom
6app:constraint_referenced_ids="text1,text2"/>
则Barrier始终位于text1,text2两个View最⼤宽度的右边,⽰意图如下:
这⾥基本的⽤法就讲完了。
下⾯再考虑⼀个情况,假如有如下的布局:
1<?xmlversion="1.0"encoding="utf-8"?>
2
3...>
4
5
6android:id="@+id/a"
7...
8android:layout_marginTop="20dp"
9/>
10
11
12android:id="@+id/b"
13...
14android:layout_marginTop="40dp"
15/>
16
17
18android:id="@+id/barrier"
19...
20app:barrierDirection="top"
21app:constraint_referenced_ids="a,b"/>
22
23
24android:id="@+id/c"
25...
26app:layout_constraintTop_toTopOf="@+id/barrier"/>
27
⽬前ButtonC和Buttona、b的最上值对齐,没有问题。但如果aGone了呢?效果如下:
其实也是符合逻辑,agone后,会变为⼀个点,所以C顶齐⽗布局也没问题。但有的时候这不符合我们的需求,我们希望Barrier不要关注
Gone的View了,所以⾕歌提供了属性barrierAllowsGoneWidgets,设为fal后,就不在关注Gone的View了,效果如下:
四、结束
本篇已基本上介绍完ConstraintLayout所有的属性了(除了代码写布局的ConstraintSet类)。相信ConstraintLayout之后会越来越强⼤。
本文发布于:2023-01-01 16:49:37,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/73084.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |