## 参考
[官方文档——使用 ConstraintLayout 构建自适应界面](https://developer.android.google.cn/training/constraint-layout?hl=zh_cn)
[GitHub 上的约束布局示例项目](https://github.com/android/views-widgets-samples/tree/master/ConstraintLayoutExamples)
[约束布局ConstraintLayout用法全解析](https://www.jianshu.com/p/502127a493fb)
[带你了解 Android 约束布局 ConstraintLayout](https://mp.weixin.qq.com/s?__biz=MzIwMTAzMTMxMg==&mid=2649493172&idx=1&sn=70d1ff879246fc49dcb90bc387eef37b&chksm=8eec854bb99b0c5d43fb3b945d4394dd67e3c09916e3e5c6a7ca98525aede0ddd3945ad1882a&scene=38#wechat_redirect)
[ConstraintLayout 约束布局](https://juejin.im/post/5cf868f2e51d45775e33f529#heading-17)
[布局优化:9种让你不得不使用约束布局Constraintlayout的场景](https://juejin.im/post/5e7eb53451882573866b7f2d)
[布局之ConstraintLayout 约束布局](https://blog.csdn.net/weixin_41620505/article/details/99688871)
## 要点摘要
[`ConstraintLayout`](https://developer.android.google.cn/reference/androidx/constraintlayout/widget/ConstraintLayout?hl=zh_cn)可让您使用扁平视图层次结构(无嵌套视图组)创建复杂的大型布局。它与[`RelativeLayout`](https://developer.android.google.cn/reference/android/widget/RelativeLayout?hl=zh_cn)相似,其中所有的视图均根据同级视图与父布局之间的关系进行布局,但其灵活性要高于`RelativeLayout`,并且更易于与 Android Studio 的布局编辑器配合使用。
`ConstraintLayout`的所有功能均可直接通过布局编辑器的可视化工具来使用,因为布局 API 和布局编辑器是专为彼此构建的。 因此,您完全可以使用`ConstraintLayout`通过拖放的形式(而非修改 XML)来构建布局。
### 约束条件概览
要在`ConstraintLayout`中定义某个视图的位置,您**必须为该视图添加至少一个水平约束条件和一个垂直约束条件**。每个约束条件均表示与**其他视图、父布局或隐形引导线**之间连接或对齐方式。每个约束条件均定义了视图在竖轴或者横轴上的位置;因此**每个视图在每个轴上都必须至少有一个约束条件**,但**通常情况下会需要更多约束条件**。**如果视图没有任何约束条件,则会在位置 \[0,0\](左上角)处进行绘制。**
示例如下:
:-: ![](https://img.kancloud.cn/cf/2b/cf2be3095269d587bad9f0a8087e745a_464x224.png)
**图 1**.编辑器将视图 C 显示在视图 A 下方,但它并没有垂直约束条件
:-: ![](https://img.kancloud.cn/51/40/51406c78b94d0e1f3b016a1fcc16d1d7_464x224.png)
**图 2**.视图 C 现垂直约束在视图 A 下方
在图 1 中,布局在编辑器中看起来很完美,但视图 C 上却没有垂直约束条件。在设备上绘制此布局时,虽然视图 C 与视图 A 的左右边缘水平对齐,但由于没有垂直约束条件,它会显示在屏幕顶部。**一旦设置C的垂直约束条件,比如在A的正下方,那么这时C会随着A的移动而移动。**
尽管缺少约束条件不会导致出现编译错误,但布局编辑器会将缺少约束条件作为错误显示在工具栏中。要查看错误和其他警告,请点击**Show Warnings and Errors**![](https://developer.android.google.cn/studio/images/buttons/layout-editor-errors.png?hl=zh_cn)。 为帮助您避免出现缺少约束条件这一问题,布局编辑器会使用[Autoconnect 和 Infer Constraints](https://developer.android.google.cn/training/constraint-layout?hl=zh_cn#use-autoconnect-and-infer-constraints)功能自动为您添加约束条件,如下图3、4所示
![](https://img.kancloud.cn/84/85/848579b314d599aaab7e58151844d8a2_1865x787.png)
![](https://img.kancloud.cn/fa/00/fa00ea95d62225f76da7ef7e30992489_1869x786.png)
### 添加或移除约束条件
创建约束条件时,请注意以下规则:
* 每个视图都必须至少有两个约束条件:一个水平约束条件,一个垂直约束条件。
* 您只能在共用同一平面的约束手柄与定位点之间创建约束条件。因此,视图的垂直平面(左侧和右侧)只能约束在另一个垂直平面上;而基准线则只能约束到其他基准线上。
* 每个约束句柄只能用于一个约束条件,但您可以在同一定位点上创建多个约束条件(从不同的视图)。
您可以通过执行以下任一操作来删除约束条件:
* 点击某个约束条件将其选中,然后按`Delete`。
* 按住`Control`(在 macOS 上为`Command`),然后点击某个约束定位点。请注意,该约束条件变为红色即表示您可以点击将其删除,如图5 所示。
![](https://img.kancloud.cn/1b/63/1b63cd1fb8467f0fba044d4c17f1b730_496x548.png)
**图 5**.红色约束条件表示您可以点击将其删除。
* 在**Attributes**窗口的 Layout 部分中,点击某个约束定位点,如图 6 所示
![](https://img.kancloud.cn/b3/29/b32973ba6913dd6b8a34eda89bbda64b_808x472.png)
**图6**.点击约束定位点将其删除。
* 当然也可以通过工具栏的**Clear All Constraints**按钮,注意这样会清除所有控件的约束条件,如图7所示
:-: ![](https://img.kancloud.cn/af/30/af3039398c767f1794950efc7130ad1b_1062x683.png)
**图7**.清除约束条件
![](https://img.kancloud.cn/be/ae/beae2208e6c86978c53d6ce004959edf_1583x701.gif)
### 父级位置
将视图的一侧约束到布局的相应边缘。
在图 8 中,视图的左侧连接到父布局的左边缘。您可以使用外边距来定义距离边缘的距离。
:-: ![](https://img.kancloud.cn/21/7f/217ff9174ae2748884e48a50700fe3f3_464x224.png)
**图 8**.对父级的水平约束
### 顺序位置
定义两个视图的显示顺序(垂直或水平方向)。
:-: ![](https://img.kancloud.cn/8f/4e/8f4e0c07429347faf0fb13fee200a16a_460x220.png)
**图 9**.水平和垂直约束方式
在图 9 中,B 被约束为始终位于 A 的右侧,而 C 被约束在 A 的下方。 不过,这些约束条件并不意味着对齐,因此 B 仍然可以上下移动。
### 对齐方式
将一个视图的边缘与另一视图的同一边对齐。
:-: ![](https://img.kancloud.cn/49/61/496157db1ce05030b36ffbc37f7a58bb_220x221.png)
**图 10**.水平对齐约束
:-: ![](https://img.kancloud.cn/d1/12/d1122c422f3be594da06c0b64b8c76da_220x220.png)
**图 11**.偏移水平对齐约束
在图 10 中,B 的左侧与 A 的左侧对齐。 如果要与视图中心对齐,请对两侧创建约束条件。
您可以通过从约束布局向内拖动视图来偏移对齐量。例如,图 11 显示 B 的偏移对齐为 24dp。 偏移量由受约束视图的外边距定义。
您还可以选择要对齐的所有视图,然后点击工具栏中的**Align**![](https://developer.android.google.cn/studio/images/buttons/layout-editor-align.png?hl=zh_cn)以选择对齐类型。
### 基线对齐
将一个视图的文本基线与另一视图的文本基线对齐。
:-: ![](https://img.kancloud.cn/97/0b/970b64869c12ce23f5bbfd0f9f8291f2_460x220.png)
**图 12**.基线对齐约束
在图 12 中,B 的第一行与 A 中的文本对齐。
要创建基线约束条件,请右键点击要约束的文本视图,然后点击**Show Baseline**。接着点击文本基线并将其拖到另一基线上。
### 引导线约束
您可以添加垂直或水平的引导线来约束视图,并且应用用户看不到该引导线。 您可以根据相对于布局边缘的 dp 单位或百分比在布局中定位引导线。
要创建引导线,请点击工具栏中的**Guidelines**![](https://developer.android.google.cn/studio/images/buttons/layout-editor-guidelines.png?hl=zh_cn),然后点击 Add Vertical Guideline 或 Add Horizontal Guideline。
拖动虚线将其重新定位,然后点击引导线边缘的圆圈以切换测量模式。
:-: ![](https://img.kancloud.cn/e4/e4/e4e4cc25ee63b34308083f7f01692eea_464x242.png)
**图 13**.受引导线约束的视图
### 屏障约束(Barrier)
与引导线类似,屏障是一条隐藏的线,您可以用它来约束视图。屏障不会定义自己的位置;相反,屏障的位置会随着其中所含视图的位置而移动。如果您希望将视图限制到一组视图而不是某个特定视图,这就非常有用。
例如,图 14 显示视图 C 被约束在屏障的右侧。该屏障设置为视图 A 和视图 B 的“end”侧(或从左至右布局中的右侧)。因此,屏障根据视图 A 或视图 B 的右侧是否为最右侧来移动。
要创建屏障,请按以下步骤操作:
1. 点击工具栏中的**Guidelines**![](https://developer.android.google.cn/studio/images/buttons/layout-editor-guidelines.png?hl=zh_cn),然后点击 Add Vertical Barrier 或 Add Horizontal Barrier。
2. 在**Component Tree**窗口中,选择要放入屏障内的视图,然后将其拖动到屏障组件中。
3. 在**Component Tree**中选择障碍,打开 Attributes![](https://developer.android.google.cn/studio/images/buttons/window-properties.png?hl=zh_cn)窗口,然后设置 barrierDirection。
现在,您可以从另一个视图创建屏障约束。
您还可以将屏障*内*的视图约束到屏障。这样,您就可以确保屏障中的所有视图始终相互对齐,即使您并不知道哪个视图最长或最高。
您还可以在屏障内添加引导线,以确保屏障的位置“最小”。
:-: ![](https://img.kancloud.cn/00/b2/00b2f2247c666d7ffe8e7c69c0ff6a0c_920x964.png)
**图 14**.视图 C 约束在屏障内,该屏障会根据视图 A 和视图 B 的位置/尺寸而移动
![](https://img.kancloud.cn/6c/0e/6c0ee8341ddde114442ec236a364ed79_814x767.png)
## 调整视图尺寸
您可以使用角手柄来调整视图的尺寸,但这会对尺寸进行硬编码,从而使视图不会针对不同的内容或屏幕尺寸进行调整。要选择不同的尺寸模式,请点击视图,然后打开编辑器右侧的**Attributes**![](https://developer.android.google.cn/studio/images/buttons/window-properties.png?hl=zh_cn)窗口。
:-: ![](https://img.kancloud.cn/59/42/5942a5efe45aa0de8b3984d74a776c79_1043x964.png)
**图 15**.在选择视图时,**Attributes**窗口会包含如下控件:**①** 尺寸比、**②** 删除约束条件、**③** 高度/宽度模式、**④** 外边距和**⑤** 约束偏差。您还可以通过点击**⑥** 约束列表中的各个约束条件来突出显示布局编辑器中的各个约束条件。
![](https://img.kancloud.cn/01/0d/010d127cd1cb5f400cf26cff8f1b5b71_1584x701.gif)
**Attributes**窗口顶部附近的视图检查器中包括若干布局属性的控件,如图 15 所示(仅适用于约束布局中的视图)。
您可以通过点击图 15 中标注**③**所指示的符号来更改高度和宽度的计算方式。这些符号代表如下所示的尺寸模式(点击符号即可切换这些设置):
* ![](https://developer.android.google.cn/studio/images/buttons/layout-width-fixed.png?hl=zh_cn)**Fixed**:您可以在下面的文本框中指定具体维度(固定大小长度宽度),也可以在编辑器中调整视图尺寸。
* ![](https://developer.android.google.cn/studio/images/buttons/layout-width-wrap.png?hl=zh_cn)**Wrap Content**:视图仅在需要时扩展以适应其内容。
* ![](https://developer.android.google.cn/studio/images/buttons/layout-width-match.png?hl=zh_cn)**Match Constraints**:视图会尽可能扩展,以满足每侧的约束条件(在考虑视图的外边距之后)。不过,您可以使用以下属性和值修改该行为(这些属性仅在您将视图宽度设置为“match constraints”时才会生效):
* **layout\_constraintWidth\_default**
* **spread**:尽可能扩展视图以满足每侧的约束条件。这是默认行为。
* **wrap**:仅在需要时扩展视图以适应其内容,但如有约束条件限制,视图仍然可以小于其内容。因此,它与使用**Wrap Content**(上面)之间的区别在于,将宽度设为**Wrap Content**会强行使宽度始终与内容宽度完全匹配;而使用**layout\_constraintWidth\_default**设置为**wrap**的**Match Constraints**时,视图可以小于内容宽度。
* **layout\_constraintWidth\_min**
该视图的最小宽度采用`dp`维度。
* **layout\_constraintWidth\_max**
该视图的最大宽度采用`dp`维度。
**注意**:您无法将`match_parent`用于`ConstraintLayout`中的任何视图。请改用“match constraints” (`0dp`)。
### 将尺寸设置为比率
如果至少有一个视图尺寸设置为“match constraints”`0dp`,那么您可以将视图尺寸设置为 16:9。要启用该比率,请点击**Toggle Aspect Ratio Constraint**(图 15 中的标注①),然后在出现的输入框中输入width:height比率。
如果宽度和高度都设置为“match constraints”,您可以点击**Toggle Aspect Ratio Constraint**,选择哪个维度基于与另一个维度的比率。 视图检查器通过用实线连接相应的边缘来指明哪个被设为比率。
例如,如果您将两侧都设置为“match constraints”,请双击**Toggle Aspect Ratio Constraint**,将宽度设置为与高度的比率。现在整个尺寸由视图的高度决定(可以以任意方式定义),如图 16 所示。
:-: ![](https://img.kancloud.cn/be/ad/bead85db3d71716fdaf4d67761b5d722_840x736.png)
**图 16**.该视图的宽高比设置为 16:9,其宽度基于与高度的比率
## 使用链控制线性组
链是一组视图,这些视图通过双向位置约束条件相互链接到一起。链中的视图可以垂直或水平分布。
链可以采用以下几种样式之一:
1. **Spread**:视图是均匀分布的(在考虑外边距之后)。这是默认值。
2. **Spread inside**:第一个和最后一个视图固定在链两端的约束边界上,其余视图均匀分布。
3. **Weighted**:当链设置为 spread 或 spread inside 时,您可以通过将一个或多个视图设置为“match constraints”(`0dp`) 来填充剩余空间。默认情况下,设置为“match constraints”的每个视图之间的空间均匀分布,但您可以使用`layout_constraintHorizontal_weight`和`layout_constraintVertical_weight`属性为每个视图分配重要性权重。如果您熟悉[线性布局](https://developer.android.google.cn/guide/topics/ui/layout/linear?hl=zh_cn)中的`layout_weight`的话,就会知道该样式与它的原理是相同的。因此,权重值最高的视图获得的空间最大;相同权重的视图获得同样大小的空间。
4. **Packed**:视图打包在一起(在考虑外边距之后)。 然后,您可以通过更改链的头视图偏差调整整条链的偏差(左/右或上/下)。
链的“头”视图(水平链中最左侧的视图以及垂直链中最顶部的视图)以 XML 格式定义链的样式。不过,您可以通过右键选择任意一个组件,右键选择Cycle Chain mode,在**spread**、**spread inside**和**packed**之间进行切换。或者选择任意一个组件,在编辑器最右边的Attributes属性编辑区域,搜索框输入chainstyle,在`layout_constraintHorizontal_chainStyle`选择具体的stylemode,如下动图所示
![](https://img.kancloud.cn/48/41/4841c48190bc7b179443d072badfb530_1349x827.gif)
:-: ![](https://developer.android.google.cn/training/constraint-layout/images/constraint-chain_2x.png?hl=zh_cn)
**图 19**.具有两个视图的水平链
:-: ![](https://developer.android.google.cn/training/constraint-layout/images/constraint-chain-styles_2x.png?hl=zh_cn)
**图 17**.每种链样式的示例
要创建链,请选择要包含在链中的所有视图,右键点击其中一个视图,选择**Chains**,然后选择 Center Horizontally 或 Center Vertically,如动图 中所示:
:-: ![](https://img.kancloud.cn/f3/8d/f38d523bfd4b32837e79c823d61ace07_706x516.gif)
**动图**.创建水平链
以下是使用链时需要考虑的其他事项:
* 视图可以是水平链和垂直链的一部分,因此可以轻松构建灵活的网格布局。
* 只有当链的每一端都被约束到同一轴上的另一个对象时,链才能正常工作,如图 15 所示。
* 虽然链的方向为垂直或水平,但使用其中一个方向不会沿该方向与视图对齐。因此,请务必包含其他约束条件,以便使链中的每个视图都能正确定位,例如[对齐约束](https://developer.android.google.cn/training/constraint-layout?hl=zh_cn#alignment)。
- 前言
- Android系统的体系结构
- Dalvik VM 和 JVM 的比较
- Android 打包应用程序并安装的过程
- Android ADB工具
- Android应用开发
- Android UI相关知识总结
- Android 中window 、view、 Activity的关系
- Android应用界面
- Android中的drawable和bitmap
- AndroidUI组件adapterView及其子类和Adapter的关系
- Android四大组件
- Android 数据存储
- SharedPreference
- Android应用的资源
- 数组资源
- 使用Drawable资源
- Material Design
- Android 进程和线程
- 进程
- 线程
- Android Application类的介绍
- 意图(Intent)
- Intent 和 Intent 过滤器(Google官网介绍)
- Android中关于任务栈的总结
- 任务和返回栈(官网译文)
- 总结
- Android应用安全现状与解决方案
- Android 安全开发
- HTTPS
- 安卓 代码混淆与打包
- 动态注入技术(hook技术)
- 一、什么是hook技术
- 二、常用的Hook 工具
- Xposed源码剖析——概述
- Xposed源码剖析——app_process作用详解
- Xposed源码剖析——Xposed初始化
- Xposed源码剖析——hook具体实现
- 无需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid应用
- 四、Hook原生应用程序
- 五、Hook 检测/修复
- Android 应用的逆向与加固保护技术
- OpenCV在Android中的开发
- Android高级开发进阶
- 高级UI
- UI绘制流程及原理
- Android新布局ConstraintLayout约束布局
- 关键帧动画
- 帧动画共享元素变换
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
- 为什么 Android 要采用 Binder 作为 IPC 机制?
- JVM 中一个线程的 Java 栈和寄存器中分别放的是什么?
- Android源码的Binder权限是如何控制?
- 如何详解 Activity 的生命周期?
- 为什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了吗?
- Android屏幕刷新机制