我以前写过一篇 ConstraintLayout 的文章如今已经到了 2018 年,最新正式版本也已经到了 1.1.2 ,又加了很多好用的特性,能够说这个约束布局已经成为 Android 中最强大的布局了,绝对不是吹嘘。android
本篇文章只会讲怎么使用代码画布局,可视化的方式精准度方面仍是有点差强人意,若是你想了解可视化方式,请看我以前的文章。bash
让咱们看一看这个 Android 中最强大的布局吧!app
相对定位约束布局最基本也最经常使用的使用方式ide
咱们先简单看一下用法工具
<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 属性,我也就不细说了ui
咱们再看 B 控件,B 的位置怎么来的呢? google
app:layout_constraintTop_toTopOf="@+id/a"
B 的顶部与 A 的顶部对齐app:layout_constraintLeft_toRightOf="@+id/a"
B 的左边与 A 的右边对齐B 控件我没有设置 margin 因此他们是贴在一块的spa
从上面的例子咱们看到了两个问题code
app:layout_constraintXXX_toXXXOf="xxx"
属性的值不同,一个写的是控件 ID,一个是 parent ,这是什么意思呢?通常控件去约束须要一个参照物,这个参照物标识能够是控件的 ID ,也能够是父布局(父容器) —— parent就比如一根绳子一端拴在当前控件的某一位置,另外一端拴在参照物的某一个位置上,这就创建起了约束。
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" 属性。 这个属性有三种值
我贴几张图大概看一下样子
固然若是是垂直的就是 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 属性还用你说?固然了我并不会说,我要说的是 layout_goneMarginStart
没见过吧?这个是什么意思呢,若是要约束控件隐藏了,B 控件位置还想保持不动怎么办呢,那么这是个什么状况呢?
给咱们的 B 控件加上两个属性
app:layout_goneMarginLeft="100dp"
app:layout_goneMarginTop="30dp"
复制代码
预想的效果很棒,不是吗,今后咱们看出 goneMarginXXXX 就是在约束的目标控件隐藏时才会生效的 margin。
若是你的控件宽或高是 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
这是横向的分析,竖向与这个一致
1、 辅助定位线 Guideline 是一个帮助咱们来定位控件,可是他又不被用户所感知。
<android.support.constraint.Guideline
android:id="@+id/line"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_height="wrap_content"/>
复制代码
上面的最基本的写法
若是上述三种属性同时出现,优先级由高到低 layout_constraintGuide_percent > layout_constraintGuide_begin > layout_constraintGuide_end
2、 控件组 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" />
复制代码
,
号隔开3、 控件屏障 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" />
复制代码
,
号隔开下面分析一个例子
<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"/>
复制代码
放一张效果图
app:barrierDirection="right"
这个属性控制的,若是改为 left 就会变成以下的样子,全都和屏障的左边去对齐了这个屏障有点稍微复杂那么一丢丢,你们多多实践一下
OK 我在这里写了约束布局的一些用法,那么下一篇我将会继续絮叨絮叨这个约束布局在咱们日常开发经常使用的一些写法和技巧!
若是还有些看不懂,请配合官方文档食用,毕竟官方资料才是咱们的一手资料