ConstraintLayout辅助类
# 1. Guideline参考线
Guideline
是一条参考线,可以帮助开发者进行辅助定位,并且实际上它并不会真正显示在布局中,像是数学几何中的辅助线一样,使用起来十分方便,出场率很高,Guideline
也可以用来做一些百分比分割之类的需求,有着很好的屏幕适配效果,Guideline
有水平和垂直方向之分,位置可以使用针对父级的百分比或者针对父级位置的距离
android:orientation="horizontal|vertical" 辅助线的对齐方式
app:layout_constraintGuide_percent="0-1" 距离父级宽度或高度的百分比(小数形式)
app:layout_constraintGuide_begin="" 距离父级起始位置的距离(左侧或顶部)
app:layout_constraintGuide_end="" 距离父级结束位置的距离(右侧或底部)
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/layout_description_tip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.946" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.04136253" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.96107054" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.05" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.2" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.4" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/imageView"
android:layout_width="120dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline3"
app:layout_constraintVertical_bias="0.0"
android:src="@drawable/user_icon_head"
android:contentDescription="@string/user_head_icon" />
<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints=""
android:ems="10"
android:hint="@string/user_head_photo"
android:inputType="textPersonName"
android:minHeight="48dp"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<EditText
android:id="@+id/editTextTextPersonName3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints=""
android:ems="10"
android:hint="@string/password_edit_text"
android:inputType="textPersonName"
android:minHeight="48dp"
app:layout_constraintBottom_toTopOf="@+id/guideline7"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline6" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/username_edit_text"
app:layout_constraintBottom_toTopOf="@+id/guideline8"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline7" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
上图中设置了水平方向位置在父级垂直方向的Guideline
,这样无论布局如何更改,Guideline
的位置始终都会是父级垂直方向的位置,控件的位置也不会偏离预设
# 2. Barrier屏障
这个Barrier
和Guideline
一样,也不会实际出现在布局中,它的作用如同其名,形成一个屏障、障碍,使用也非常多。这里借助constraintlayout网站 (opens new window)来讲解Barrier
。例子如下:
当我们创建布局时,有时会遇到布局可以根据本地化而更改的情况。这里借助有一个非常简单的例子
这里有三个文本视图:左边的textView1
和textView2
;右边的textView3
。textView3
被限制在textView1
的末尾,这工作得很好——它完全根据我们需要来定位和大小textView3
。
但是,如果我们需要支持多种语言,事情就会变得更加复杂。如果我们添加一个德语翻译,那么我们就会遇到问题,因为在英文版本中,textView1
中的文本比textView2
中的文本长,而在德语中,textView2
中的文本比textView1
长:
这里的问题在于textView3
仍然是相对于textView1
的,所以textView2
直接插入了textView3
中。在设计视图里看起来更明显(白色背景的那个)。比较直接的解决办法是使用TableLayout
,或者把 textView1
& textView2
包裹在一个垂直的,android:layout_width="wrap_content"
的 LinearLayout中
。然后让textView3
约束在这个LinearLayout
的后面。但是我们有更好的办法:Barriers
。Barriers
的配置属性如下:
<!-- 用于控制Barrier相对于给定的View的位置 -->
app:barrierDirection="top|bottom|left|right|start|end"
<!-- 取值是要依赖的控件的id,Barrier将会使用ids中最大的一个的宽/高作为自己的位置 -->
app:constraint_referenced_ids="id,id"
2
3
4
5
修改过后的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/warehouse"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="@string/hospital"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView1" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="textView2,textView1" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:maxWidth="290dp"
android:paddingStart="8dp"
android:text="@string/lorem_ipsum"
app:layout_constrainedWidth="true"
app:layout_constraintStart_toEndOf="@+id/barrier7"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
为了看到整体的效果,可以切换语言,此时你会看到Barrier
会自动位于较宽的那个textView
后面,也就间接让textView3
也位于了正确的位置。
上述例子是直接使用的constraintlayout网站 (opens new window)中的例子,可以直接访问链接进行查看。
# 3. Group组
工作当中常常会有很多个控件同时隐藏或者显示的场景,传统做法要么是进行嵌套,对父布局进行隐藏或显示,要么就是一个一个设置,这显然都不是很好的办法,ConstraintLayout
中的Group
就是来解决这个问题的。Group
的作用就是可以对一组控件同时隐藏或显示,没有其他的作用,它的属性如下:
app:constraint_referenced_ids="id,id" 加入组的控件id
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/textViewA"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="56dp"
android:background="#87ffff"
android:gravity="center"
android:text="A"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.115"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textViewB"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="280dp"
android:background="#87ffc3"
android:gravity="center"
android:text="B"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.758"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textViewC"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="164dp"
android:background="#ffff87"
android:gravity="center"
android:text="C"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.437"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:constraint_referenced_ids="textViewA,textViewB,textViewC" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
A、B、C三个view
,受Group
控制,当Group
的visibility
为visible
时,它们都是正常显示的,设置为gone
时,它们都会隐藏
# 4. Placeholder占位符
Placeholder
的作用就是占位,它可以在布局中占好位置,通过app:content=""
属性,或者动态调用setContent()
设置内容,来让某个控件移动到此占位符中
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/A"
android:layout_width="100dp"
android:layout_height="60dp"
android:background="#ffff87"
android:gravity="center"
android:text="A"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Placeholder
android:layout_width="100dp"
android:layout_height="60dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
当我们设置app:content="@+id/A"
或者调用setContent()
时,控件A就会被移动到Placeholder
中,当然在布局中使用app:content=""
显然就失去了它的作用。
# 5. Flow流式虚拟布局
Flow
是用于构建链的新虚拟布局,当链用完时可以缠绕到下一行甚至屏幕的另一部分。当您在一个链中布置多个项目时,这很有用,但是您不确定容器在运行时的大小。您可以使用它来根据应用程序中的动态尺寸(例如旋转时的屏幕宽度)构建布局。Flow
是一种虚拟布局。在ConstraintLayout
中,虚拟布局(Virtual layouts
)作为virtual view group
的角色参与约束和布局中,但是它们并不会作为视图添加到视图层级结构中,而是仅仅引用其它视图来辅助它们在布局系统中完成各自的布局功能。
下面使用动画来展示Flow创建多个链将布局元素充裕地填充一整行:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/A"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="A"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/B"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="B"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/C"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="C"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/D"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="D"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/E"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:constraint_referenced_ids="A,B,C,D,E"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
# 5.1 链约束
Flow
的constraint_referenced_ids
关联的控件是没有设置约束的,这一点和普通的链是不一样的,这种排列方式是Flow
的默认方式none
,我们可以使用app:flow_wrapMode=""
属性来设置排列方式,并且我们还可以使用flow_horizontalGap
和flow_verticalGap
分别设置两个view
在水平和垂直方向的间隔,下面我们再添加几个控件来展示三种排列方式:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/A"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="A"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/B"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="B"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/C"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="C"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/D"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="D"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/E"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/F"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/G"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/H"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/I"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#c3ff87"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I"
app:flow_wrapMode="none"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
- none(默认值):所有引用的
view
形成一条链,水平居中,超出屏幕两侧的view
不可见
- chain:所引用的
view
形成一条链,超出部分会自动换行,同行的view
会平分宽度。
- aligned:所引用的
view
形成一条链,但view
会在同行同列。
下面使用动画来展示三种效果的变化
当flow_wrapMode
的值是chian
或aligned
时,我们还可以针对不同的链进行配置,这里就不一一展示效果了,具体的属性如下:
app:flow_horizontalStyle="packed|spread|spread_inside" 所有水平链的配置
app:flow_verticalStyle="packed|spread|spread_inside" 所有垂直链的配置
app:flow_firstHorizontalStyle="packed|spread|spread_inside" 第一条水平链的配置,其他条不生效
app:flow_firstVerticalStyle="packed|spread|spread_inside" 第一条垂直链的配置,其他条不生效
app:flow_lastHorizontalStyle="packed|spread|spread_inside" 最后一条水平链的配置,其他条不生效
app:flow_lastVerticalStyle="packed|spread|spread_inside" 最后一条垂直链的配置,其他条不生效
2
3
4
5
6
7
# 5.2 对齐约束
上面展示的都是相同大小的view
,那么不同大小view
的对齐方式,Flow
也提供了相应的属性进行配置
<!-- top:顶对齐、bottom:底对齐、center:中心对齐、baseline:基线对齐 -->
app:flow_verticalAlign="top|bottom|center|baseline"
<!-- start:开始对齐、end:结尾对齐、center:中心对齐 -->
app:flow_horizontalAlign="start|end|center"
2
3
4
5
使用flow_verticalAlign
时,要求orientation
的方向是horizontal
,而使用flow_horizontalAlign
时,要求orientation
的方向是vertical
下面展示下各个效果:
horizontal 水平排列
- top
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="top"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
- bottom
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="bottom"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
- center
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="center"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
- baseline
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="baseline"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
以上例子代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/A"
android:layout_width="90dp"
android:layout_height="90dp"
android:gravity="center"
android:text="A"
android:background="#ff8787"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/B"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#ff8787"
android:gravity="center"
android:text="B"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/C"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#ff8787"
android:gravity="center"
android:text="C"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/D"
android:layout_width="120dp"
android:layout_height="120dp"
android:background="#ff8787"
android:gravity="center"
android:text="D"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/E"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#ff8787"
android:gravity="center"
android:text="E"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/F"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#ff8787"
android:gravity="center"
android:text="F"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/G"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#ff8787"
android:gravity="center"
android:text="G"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/H"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#ff8787"
android:gravity="center"
android:text="H"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/I"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#ff8787"
android:gravity="center"
android:text="I"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/J"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#ff8787"
android:gravity="center"
android:text="J"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="baseline"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
垂直方向排列同理,这里就不再作过多的展示了
# 5.3 数量约束
当flow_wrapMode
属性为aligned
和chian
时,通过flow_maxElementsWrap
属性控制每行最大的子View
数量,例如我们设置为flow_maxElementsWrap=4
,效果图如下:
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal"
app:flow_maxElementsWrap="4"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
app:flow_verticalAlign="baseline"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
9
10
# 6. Layer(层布局)
Laye继承自ConstraintHelper,是一个约束助手,相对于Flow来说,Layer的使用较为简单,常用来增加背景,或者共同动画,图层 (Layer
) 在布局期间会调整大小,其大小会根据其引用的所有视图进行调整,代码的先后顺序也会决定着它的位置,如果代码在所有引用view
的最后面,那么它就会在所有view
的最上面,反之则是最下面,在最上面的时候如果添加背景,就会把引用的view
覆盖掉,下面展示下添加背景的例子,做动画的例子这里不再展示了
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<androidx.constraintlayout.helper.widget.Layer
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/rounded_border"
android:padding="10dp"
app:constraint_referenced_ids="AndroidImg,NameTv" />
<ImageView
android:id="@+id/AndroidImg"
android:layout_width="150dp"
android:layout_height="120dp"
android:src="@drawable/android"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/NameTv"
android:layout_width="100dp"
android:layout_height="40dp"
android:gravity="center"
android:text="Android"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="@id/AndroidImg"
app:layout_constraintStart_toStartOf="@id/AndroidImg"
app:layout_constraintTop_toBottomOf="@id/AndroidImg" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
素材图片
可以看到,当Layer
的代码在所有引用view
的上面时,效果是正常的,因为此时所有的view
都在Layer
的上面,下面我们来看一下Layer
代码在最后面时的情况:
代码内容不变,变更layer的顺序位置
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<ImageView
android:id="@+id/AndroidImg"
android:layout_width="150dp"
android:layout_height="120dp"
android:src="@drawable/android"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/NameTv"
android:layout_width="100dp"
android:layout_height="40dp"
android:gravity="center"
android:text="Android"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="@id/AndroidImg"
app:layout_constraintStart_toStartOf="@id/AndroidImg"
app:layout_constraintTop_toBottomOf="@id/AndroidImg" />
<androidx.constraintlayout.helper.widget.Layer
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/rounded_border"
android:padding="10dp"
app:constraint_referenced_ids="AndroidImg,NameTv" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
我们可以看到,此时Layer
已经把所有的view
覆盖住了
# 7. ImageFilterButton & ImageFilterView
ImageFilterButton 和 ImageFilterView是两个控件,他们之间的关系就和ImageButto 与 ImageView 是一样的,所以这里就只拿 ImageFilterView 来做讲解。从名字上来看,它们的定位是和过滤有关系的,它们的大致作用有两部分,一是可以用来做圆角图片,二是可以叠加图片资源进行混合过滤,下面一一展示:
# 7.1 圆角图片
ImageFilterButton 和 ImageFilterView可以使用两个属性来设置图片资源的圆角,分别是
roundPercent
:接受的值类型是0-1的小数,根据数值的大小会使图片在方形和圆形之间按比例过度round
:可以设置具体圆角的大小
以小米的新logo为例:
素材图片采用方形Logo
roundPercent属性设置后:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/xiaomi_ractangle_logo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:roundPercent="0.6" />
</androidx.constraintlayout.widget.ConstraintLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
使用roundPercent
设置了圆角为0.6(60%),实现一个圆角图片就是如此简单
父布局为相对布局时,依然生效
# 7.2 图片过滤
ImageFilterButton 和 ImageFilterView不但可以使用src
来设置图片资源,还可以使用altSrc
来设置第二个图片资源,altSrc
提供的资源将会和src
提供的资源通过crossfade
属性形成交叉淡化效果,默认情况下,crossfade=0
,altSrc
所引用的资源不可见,取值在0-1
<androidx.constraintlayout.utils.widget.ImageFilterView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/jetpack_logo"
app:altSrc="@mipmap/kotlin_logo"
app:crossfade="0.1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
2
3
4
5
6
7
8
9
10
ImageFilterView,ImageFilterButton其他属性汇总
- 圆角 app:round,取值0-50dp,默认0,就是方形,设置50就是圆形图片,超过50没其他意义,还是圆形图片。
- 圆角比例 app:roundPercent,取值0-1之间,默认0就是方形,1是圆形图片,同上,超过1按照1处理,还是圆形图片。
- 交叉图 app:altSrc,需要跟app:crossfade共同使用,app:crossfade取值0-1,默认0为交叉图完全透明,不展示。取值1交叉图完全展示,覆盖到src上。 app:overlay,官方释义:定义alt图像是在原始图像的顶部淡入,还是与其交叉淡入。默认值为true。对于半透明对象设置为false。我没试过效果。
- 色温 app:warmt,float型,默认值1,小于1是冷色调,大于1是暖色调。
- 亮度 app:brightness,float型,默认1,值越大亮度越高。
- 饱和度 app:brightness,float型,默认1,取值0为灰阶样式,大于1的数值都是超饱和状态,色彩非常艳丽,有点辣眼睛。
- 对比度 app:contrast,float型,默认1,取值0相当于图片变全黑,大于1都是高对比度状态。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DAF3FE"
tools:context=".MainActivity"
tools:ignore="HardcodedText">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view01"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toBottomOf="@id/view02"
app:layout_constraintEnd_toStartOf="@+id/view02"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/view02"
app:warmth="0" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view02"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toTopOf="@+id/view05"
app:layout_constraintEnd_toStartOf="@+id/view03"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view01"
app:layout_constraintTop_toTopOf="parent"
app:warmth="5" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view03"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toBottomOf="@id/view02"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@+id/view02"
app:layout_constraintTop_toTopOf="@id/view02"
app:warmth="9"
tools:layout_editor_absoluteY="0dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view04"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:brightness="0"
app:layout_constraintBottom_toBottomOf="@id/view05"
app:layout_constraintEnd_toStartOf="@+id/view05"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/view05"
tools:layout_editor_absoluteY="136dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view05"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:brightness="5"
app:layout_constraintBottom_toTopOf="@+id/view8"
app:layout_constraintEnd_toStartOf="@+id/view6"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view04"
app:layout_constraintTop_toBottomOf="@+id/view02" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view6"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:brightness="9"
app:layout_constraintBottom_toBottomOf="@id/view05"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view05"
app:layout_constraintTop_toTopOf="@id/view05"
tools:layout_editor_absoluteY="136dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view7"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toBottomOf="@id/view8"
app:layout_constraintEnd_toStartOf="@+id/view8"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/view8"
app:saturation="0"
tools:layout_editor_absoluteY="285dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view8"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toTopOf="@+id/view11"
app:layout_constraintEnd_toStartOf="@+id/view9"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view7"
app:layout_constraintTop_toBottomOf="@+id/view05"
app:saturation="5" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view9"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:layout_constraintBottom_toBottomOf="@id/view8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view8"
app:layout_constraintTop_toTopOf="@id/view8"
app:saturation="9"
tools:layout_editor_absoluteY="296dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view10"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:contrast="0"
app:layout_constraintBottom_toBottomOf="@id/view11"
app:layout_constraintEnd_toStartOf="@+id/view11"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/view11"
tools:layout_editor_absoluteY="437dp" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view11"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:contrast="5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/view12"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view10"
app:layout_constraintTop_toBottomOf="@+id/view8" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/view12"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/kotlin_icon_old"
app:contrast="9"
app:layout_constraintBottom_toBottomOf="@id/view11"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/view11"
app:layout_constraintTop_toTopOf="@id/view11"
tools:layout_editor_absoluteY="437dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# 8. 边距问题的补充
有时margin
设置负值在ConstraintLayout是没有效果的(但是目前在constraintlayout-2.1.3版本上是无该问题的)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/vA"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:background="#8787ff"
android:gravity="center"
android:text="A"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/vB"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="-30dp"
android:layout_marginTop="-30dp"
android:background="#b8e994"
android:gravity="center"
android:text="B"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintLeft_toRightOf="@id/vA"
app:layout_constraintTop_toBottomOf="@id/vA" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
如果layout_marginLeft和
layout_marginTop属性未生效,可以通过轻量级的Space
来间接实现这种效果。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/vA"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:background="#ff87c3"
android:gravity="center"
android:text="A"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="@+id/space"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
app:layout_constraintBottom_toBottomOf="@id/vA"
app:layout_constraintRight_toRightOf="@id/vA" />
<TextView
android:id="@+id/vB"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="-30dp"
android:layout_marginTop="-30dp"
android:background="#87ffc3"
android:gravity="center"
android:text="B"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintLeft_toRightOf="@id/space"
app:layout_constraintTop_toBottomOf="@id/space" />
</androidx.constraintlayout.widget.ConstraintLayout>
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
【汇总文档】
[1] 使用 ConstraintLayout 构建自适应界面. https://developer.android.com/training/constraint-layout
[2] 万字长文 - 史上最全ConstraintLayout(约束布局)使用详解. https://juejin.cn/post/6949186887609221133#heading-28
[3] Barriers. https://constraintlayout.com/basics/barriers.html
[4] Constraintlayout 2.0-你们要的更新来了. https://juejin.cn/post/6854573221312725000#heading-9
[5] ConstraintLayout约束布局. https://www.sunofbeach.net/a/1236644491448922112
[6] ImageFilterView. https://developer.android.google.cn/reference/android/support/constraint/utils/ImageFilterView