Android:随笔—— 最强大的布局 ConstraintLayout
我之前写过一篇 ConstraintLayout 的文章现在已经到了 2018 年,最新正式版本也已经到了 1.1.2 ,又加了不少好用的特性,可以说这个约束布局已经成为 Android 中最强大的布局了,绝对不是吹嘘。
本篇文章只会讲怎么使用代码画布局,可视化的方式精准度方面还是有点差强人意,如果你想了解可视化方式,请看我之前的文章。
让我们看一看这个 Android 中最强大的布局吧!
相对定位
一、基本用法
相对定位约束布局最基本也最常用的使用方式
我们先简单看一下用法
<TextView android:id="@+id/a" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:gravity="center" android:layout_marginTop="30dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" android:text="A"/> <TextView android:id="@+id/b" app:layout_constraintTop_toTopOf="@+id/a" app:layout_constraintLeft_toRightOf="@+id/a" android:layout_width="60dp" android:layout_height="wrap_content" android:gravity="center" android:text="B" />
我们先看 A 控件,A 的位置怎么来的呢?
-
app:layout_constraintTop_toTopOf="parent"
A 的顶边与 parent 的顶边对齐 -
app:layout_constraintLeft_toLeftOf="parent"
A 的左边与 parent 的左边对齐
我们看到 A 与左边上边都有一个空隙, 这就是普通的 android:layout_marginXXXX 属性,我也就不细说了
我们再看 B 控件,B 的位置怎么来的呢?
-
app:layout_constraintTop_toTopOf="@+id/a"
B 的顶部与 A 的顶部对齐 -
app:layout_constraintLeft_toRightOf="@+id/a"
B 的左边与 A 的右边对齐
B 控件我没有设置 margin 所以他们是贴在一块的
从上面的例子我们看到了两个问题
- 看到两个控件
app:layout_constraintXXX_toXXXOf="xxx"
属性的值不一样,一个写的是控件 ID,一个是 parent ,这是什么意思呢?一般控件去约束需要一个参照物,这个参照物标识可以是控件的 ID ,也可以是父布局(父容器) —— parent
就好比一根绳子一端拴在当前控件的某一位置,另一端拴在参照物的某一个位置上,这就建立起了约束。
- 如果仔细看上述代码,大家肯定还有一个疑问,我明明在 A 控件上设置了 marginRight 为什么 A 和 B 还是贴着的,这就有一个说法,如果一个边没有约束那么他对应边的 margin 是不生效的
OK 理解起来很简单不是吗,约束布局最基本的语法就是 app:layout_constraint位置_to位置Of="看齐目标"
那么像这种普通的相对定位的写法有多少种呢,我来给你们列举一下,再配张图标出它们的具体位置,看完下面基本的约束布局用法你就已经了解了。
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
当然有一部分控件没有 Baseline 这个位置,所以这个位置不是对每种控件都有效的
二、圆形定位
<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/b" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintCircle="@id/a" app:layout_constraintCircleAngle="45" app:layout_constraintCircleRadius="100dp" />
偷偷放一张图片
-
app:layout_constraintCircle
需要看齐的参照物,图中 B 就是把 A 当做参照物进行约束的 -
app:layout_constraintCircleAngle
要旋转的角度,最上方 0 度,默认就是 0 度,顺时针开始算。 -
app:layout_constraintCircleRadius
两个控件中心点的距离
约束链
能够在水平或垂直方向控件之间相互约束而组成的一条链就是约束链,约束链是由开头的控件进行属性控制的。没错就是跟着大哥走
- 普通的约束链示例
<View android:id="@+id/a" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/b" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toLeftOf="@+id/c" app:layout_constraintTop_toTopOf="@+id/a" /> <View android:id="@+id/c" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_green_light" app:layout_constraintLeft_toRightOf="@+id/b" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@+id/a" />
看到 A 控件就是引领小弟们的链头,所以众小弟都听他的。我们看到它的 app:layout_constraintHorizontal_chainStyle="packed" 属性。
这个属性有三种值
- packed:控件紧挨在一起。还可以通过bias属性设置偏移量。
- spread:均与分布控件。
- spread_inside:均与分布控件,但是两边控件贴边。
我贴几张图大概看一下样子
当然如果是垂直的就是 app:layout_constraintVertical_chainStyle="xxxx" 属性
-
组合 layout_constraintHorizontal_bias 的约束链
如果链的样式是 packed 我们还能组合 layout_constraintHorizontal_bias 使用,我就不贴代码了,直接上图了解下
还有一种特殊的约束链,就是按照控件权重平分控件(明摆着抢 LinearLayout 饭碗)
<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toLeftOf="@+id/c" /> <View android:id="@+id/c" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_green_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/b" app:layout_constraintRight_toRightOf="parent" />
这种链就是不设置链的 style 而是用权重的方式进行排布。
约束布局散乱特性
一、动态推测控件的宽或高
我们约束布局还支持这样的一种情况,我们控件只确定了控件的宽、高的其中一个,然后按比例算出另一边的宽高。(当然这个需求很小众)app:layout_constraintDimensionRatio="2:1"
这个属性就是按比例推测宽高的属性
<View android:id="@+id/a" android:layout_width="100dp" android:layout_height="0dp" android:background="@android:color/holo_red_light" app:layout_constraintDimensionRatio="2:1" app:layout_constraintLeft_toLeftOf="parent" />
看以上代码 2:1 其实就是 width/height = 2/1 ,height = 50dp,所以这个属性的就是 width/height ,由此我们只要给定宽或高就能推出另一个。(当然如果你宽高都确定了设置这个属性就无效了)
这个属性的值还能设置为 (H,2:1),(W,2:1) 这样的,其实我看到之后是一脸懵逼的,但是还要硬着头皮研究,H 就是 Height,W 就是 Width,好吧说一下规律。
(H,2:1)
如果确定宽宽:高度 = 100 * 1 / 2
如果确定高度:宽度 = 100 * 1 / 2(W,2:1)
如果确定宽宽:高度 = 100 * 2 / 1
如果确定高度:宽度 = 100 * 2 / 1
虽然我这样说了但是还是不推荐用。本来就是小众功能如果想用还是用普通的写法就行了,不要带什么 H,W 了。装逼太刺眼!
二、父布局填充约束
有时候有这么一个需求想把控件按照比例填充父布局。Android 屏幕适配这么复杂,好像不容易实现
这时候约束布局有两个属性 layout_constraintWidth_percent layout_constraintHeight_percent
怎么看怎么像百分比布局,这岂不是把一直不温不火的百分比布局给革命了
<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintWidth_percent="0.3" />
我只放这么一段代码大家应该就知道怎么用了,我也就不多了说了。
默认是居中的如果想调整位置请结合
app:layout_constraintHorizontal_bias="0.3"
食用
三、聊一聊 margin 属性
有人要说了 margin 属性还用你说?当然了我并不会说,我要说的是 layout_goneMarginStart
没见过吧?这个是什么意思呢,如果要约束控件隐藏了,B 控件位置还想保持不动怎么办呢,那么这是个什么情况呢?
-
举个例子 B 控件左边相对 A 控件进行定位,并设置了 20dp 的 marginLeft。如果把 A 隐藏了会怎么样呢?分别看一下图1、图2。
给我们的 B 控件加上两个属性
app:layout_goneMarginLeft="100dp" app:layout_goneMarginTop="30dp"
预想的效果很棒,不是吗,从此我们看出 goneMarginXXXX 就是在约束的目标控件隐藏时才会生效的 margin。
四、WRAP_CONTENT 的小问题
如果你的控件宽或高是 wrap_content 并且控件长度过长时,他的约束会失效,我们看个例子
<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/b" android:layout_width="wrap_content" android:layout_height="50dp" android:background="@android:color/holo_blue_light" android:text="是事实是事实是事实是事实是事实" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/a" />
解决方式就是使用
app:layout_constrainedWidth="true" app:layout_constrainedHeight="true"
五、最小高度宽度,最大高度宽度
设置最小尺寸layout_constraintWidth_min and layout_constraintHeight_min
设置最大尺寸layout_constraintWidth_max and layout_constraintHeight_max
没啥好说的。
六、控件位置偏移
app:layout_constraintHorizontal_bias="0.3" app:layout_constraintVertical_bias="0.3"
相信这两个属性在上面大家都看过好多遍了吧,如果控件没有占满父布局,它是可以控制当前控件在父布局的空间里所占的位置,放张图理解一下。就跟拔河一样哈哈
该属性的取值范围是 0 - 1
这是横向的分析,竖向与这个一致
约束布局辅助工具
一、 辅助定位线
Guideline 是一个帮助我们来定位控件,但是他又不被用户所感知。
<android.support.constraint.Guideline android:id="@+id/line" android:layout_width="wrap_content" android:orientation="vertical" android:layout_height="wrap_content"/>
上面的最基本的写法
- id 是必须的不然怎么约束
- android:orientation="vertical" 来控制横向还是竖向,用过线性布局应该都知道这个属性
- 他核心的三个属性
- layout_constraintGuide_begin="100dp" 距离父容器起始位置的距离
- layout_constraintGuide_end="100dp" 距离父容器结束位置的距离
- layout_constraintGuide_percent="0.3" 距离父容器宽度或高度的百分比,取值范围 0 - 1
如果上述三种属性同时出现,优先级由高到低 layout_constraintGuide_percent > layout_constraintGuide_begin > layout_constraintGuide_end
二、 控件组
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="a,b" />
- android:visibility="visible" 控制显示隐藏,也可以在代码中根据 id 获取 Group 来控制显示隐藏
- app:constraint_referenced_ids="a,b" 受这个 Group 管理的控件们的 id,
,
号隔开
三、 控件屏障
Barrier
<android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="start" app:constraint_referenced_ids="button1,button2" />
- app:barrierDirection=“start” 属性可以控制这个屏障在哪个位置,具体位置可以参考文章开头那张介绍位置的图
- app:constraint_referenced_ids 屏障里面的控件们的 id,
,
号隔开
下面分析一个例子
<TextView android:id="@+id/tv_name" android:layout_width="0dp" android:layout_height="wrap_content" android:text="姓名:sdfsdfsdsdf" app:layout_constraintBottom_toBottomOf="@+id/et_name" app:layout_constraintTop_toTopOf="@+id/et_name"/> <TextView android:id="@+id/tv_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="手机号:" app:layout_constraintBottom_toBottomOf="@+id/et_phone" app:layout_constraintTop_toTopOf="@+id/et_phone"/> <EditText android:id="@+id/et_name" android:layout_width="0dp" android:layout_height="wrap_content" android:hint="请输入姓名" app:layout_constraintLeft_toLeftOf="@+id/barrier" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <EditText android:id="@+id/et_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:hint="请输入手机号" app:layout_constraintLeft_toLeftOf="@+id/barrier" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_name"/> <android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="right" app:constraint_referenced_ids="tv_name,tv_phone"/>
放一张效果图
- 首先把 et_name et_phone 位置放好,然后再把 tv_name tv_phone 放在屏障里,把他们当成一个整体
- 然后 et_name et_phone 左边约束我们的屏障
- 为什么 et_name et_phone 对齐的会是屏障的右边,因为
app:barrierDirection="right"
这个属性控制的,如果改成 left 就会变成如下的样子,全都和屏障的左边去对齐了
这个屏障有点稍微复杂那么一丢丢,大家多多实践一下
小结
OK 我在这里写了约束布局的一些用法,那么下一篇我将会继续絮叨絮叨这个约束布局在我们平常开发常用的一些写法和技巧!
如果还有些看不懂,请配合官方文档食用,毕竟官方资料才是我们的一手资料
参考资料
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
BlackHat & DEFCON现场秀:阿里安全专家演示“视频水印叠加”和“一分钟越狱iOS 11.4”
美国当地时间8月8日,两大世界顶级信息安全会议BlackHat和DEFCON将在美国拉斯维加斯正式揭幕。来自全球的数万名白帽黑客、安全厂商、高校学者、政府机构等安全从业人员齐聚,高度关注这两场盛会将来带来怎样的前沿技术饕餮盛宴,阿里安全八大实验室多名安全专家受邀参会,带来的三大议题和两项演示备受瞩目。 据悉,BlackHat和DEFCON由传奇人物Jeff Moss分别于1997年和1993年创办,不过从2014年开始才有中国白帽受邀演讲的身影。阿里安全自2015年至今已数次参加两大顶会,曾有议题被大会主席誉为“印象最深刻的演讲”。 2018年更是阿里安全大爆发之年,BlackHat的亚洲和欧洲会议已有多名安全专家议题入选,此次共有六名安全专家受邀参会,“议题演讲+现场演示”的数量占到中国互联网公司整体参会数量的五分之一,以自身能力向
- 下一篇
微信‘类’之测试方法汇总
前言 小程序优势之一,是可以同时在不同设备上运行,但这会带来潜在兼容性问题。这个问题对于个人开发者而言很麻烦,因为他们通常只会用自己的手机来测试小程序。当然,微信早就意识到这个问题,并在早先的新能力更新中,为小程序开发者提供了免费的真机测试工具。 微信提供的这个工具,不需要自己准备测试手机。这个工具已经免费为你提供了大量 Android 机型供你测试,你需要做的,就是点点鼠标、申请测试。 在最新版、测试版「微信 Web 开发者工具」中,都内置了这个工具。在开发者工具中,点击右上角的「测试」按钮,就可以查看以往申请过的测试报告。 一、真机工具下载地址 1、beta 版本微信 Web 开发者工具 2、最新版微信 Web 开发者工具正式版 二、Airtest AirtestIDE是一个跨平台的UI自动化测试编辑器,适用于游戏和App。 1、自动化脚本录制、一键回放、报告查看,轻而易举实现自动化测试流程 2、支持基于图像识别的Airtest框架,适用于所有Android和Windows游戏 3、支持基于UI控件搜索的Poco框架,适用于Unity3d,Cocos2d与Android App 4...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装Docker,最新的服务器搭配容器使用
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7安装Docker,走上虚拟化容器引擎之路