使用视图大小控键
在Android ConstraintLayout图文并茂详解(一)中,我们已经了解到如何使用视图的约束控键来添加一个约束。现在,我们要来了解拖动调整大小控键来修改视图的大小。
调整大小控键:可以拖动方形调整大小的句柄来调整元素的大小。 拖动时,手柄变成角度变角。
约束控键:单击约束句柄,在元素的每一侧显示为圆形,然后拖动到另一个约束句柄或父边界以创建约束。 约束由Z字形线表示。
从上图中,我们清楚的看到,在我们拖动调整大小控键时,视图的大小虽然可以变化,但是数值并不能实时的显示出来,只有在停止拖动以后,才可以在属性(Attributes)窗口 - inspector中看到视图修改后的大小值。这就有一个问题,拖动的不准确性,肯定不能满足UI的需求。如果是将width/height类型设置为fixed,还不如在属性(Attributes)窗口 - inspector中修改尺寸大小,不仅准确而且效率高。不由得觉得拖动调整大小控键好鸡肋。。。
height/width类型
在传统布局中,我们习惯了使用wrap_content或者match_parent以使用视图的内容或者布局的尺寸来确定视图的大小,甚至是精确地指定视图范围。ConstraintLayout与传统布局类似,而又有所不同。在ConstraintLayout中,可以通过以下3种不同的方式设置android:layout_width和android:layout_height属性来指定控件的尺寸:
:即fixed,表示固定值,也就是给视图指定了一个固定的长度或者宽度值
:表示MATCH_CONSTRAINT,或者是any size。对于ConstraintLayout中的任何视图,不应使用match_parent。在XML文件中, 臫0dp表示layout_width或layout_height属性的MATCH_CONSTRAINT值。
:表示wrap_content
对于fixed和wrap_content,这里不必多说,值得注意的一点是,是当视图的尺寸类型为wrap_content,尤其要注意视图的内容长度是否大于约束之间的距离,以避免出现视图内容覆盖的现象。 与传统布局不一样的是,在ConstraintLayout中并不支持MATCH_PARENT,尽管类似的行为可以通过使用MATCH_CONSTRAINT来定义,相应ConstraintLayout的左/右或顶部/底部约束被设置为“parent”。它们最大的区别在于,match parent是用于填充满当前视图的父布局的可用空间,而MATCH_CONSTRAINT是用于填充满当前视图的约束的可用空间,而且在此情况下,可以通过设置尺寸比例来指定视图的尺寸 。
如果要修改视图的height/width类型,我们可以这么做
在属性(Attributes)窗口 - inspector中,单击可以循环遍历height/width类型
在属性(Attributes)窗口的 layout_width和layout_height中直接设置
将尺寸设置为比例
在height/width类型中提到,当height/width类型为MATCH_CONSTRAINT时,可以通过设置尺寸比例来指定视图的尺寸。这是什么意思呢?就是,我们可以将视图的尺寸维度(宽度/高度)基于视图的另一个维度,可以将视图的高度基于视图的宽度的比例来定义,也可以将视图的宽度基于视图的高度的比例来定义。
对于比例,我们可以这么表示:
浮点数,表示宽度和高度之间的比例
“width:height”形式的比例
比如,视图的宽度为160dp,高度为0dp(即MATCH_CONSTRAINT),并将属性layout_constraintDimentionRatio设置为16:9,那么视图的高度为90dp,在属性(Attributes)窗口 - inspector中我们可以看到:
如果在xml中定义,可以这么做:
又有一种特殊情况,那就是,宽度和高度均设置为0dp(即MATCH_CONSTRAINT),这也可以使用比率。在这种情况下,其计算方式与Bitmap压缩类似,默认的是满足所有的约束的最大尺寸,并保持指定的宽高比。如果你想指定按比例计算的尺寸维度,可以这么做,可以通过在比例前面添加字幕表示:
W:用于约束宽度,此时视图的高度将与约束调节匹配:
将按照4:9的比例设置ImageView的宽度,而ImageView的高度将与约束条件匹配。
XML代码:
UI效果图:
在属性(Attributes)窗口 - inspector效果图:
H:用于约束高度,此时视图的宽度将与约束调节匹配
将按照16:9的比例设置ImageView的高度,而ImageView的宽度将与约束条件匹配。
XML代码:
UI效果图:
在属性(Attributes)窗口 - inspector:效果图:
在属性(Attributes)窗口 - inspector中,可以快速的设置尺寸比例。首先先单击切换纵横比约束,下图中红色框标注的,然后在出现的输入框中输入width:height比例。
如果要想切换指定按比例计算的尺寸维度,再次点击红色框标注的即可。如果多点,会照成约束偏差混乱,还需要自己重新调,并且约束比例又变成1:1,感觉这里好操蛋,你可以感受下~~~
值得注意的是,如果尺寸比例设置有误,会造成其超出约束条件,类似于之前提到的视图覆盖现象…尺寸比例的设置尤其要慎重,慎重,再慎重…
调整边距
对于Margin属性,跟传统布局的margin属性没啥区别,就是用来表明间隔的距离。
在XML中,用以下属性来设置margin属性值:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
我们早已熟悉在XML设置margin,这里不用多说。这里我们来看看在Layout Editor中如何快速的设置margin。
默认边距
我们可以在工具栏中设置默认边距。为什么说这是默认边距呢?
在工具栏中,我们只需修改 的值,此值便是约束的默认边距值。在设置此值以后的所有约束的边距值便是它。这样,便于我们统一设置边距。如下所示,将边距值修改为24dp,以后所有的约束的边距都是24dp:
在Design窗口中拖动视图
尽管,我不太习惯在Design窗口中拖动视图,但,其也是修改边距的一种方式,这里也了解下。视图默认的边距为24dp,然后选择视图后,通过拖动的方式修改视图的边距:
在属性(Attributes)窗口 - inspector中
在属性(Attributes)窗口 - inspector中,显示着视图的种种约束值,当然,margin也是包含在其中。
当我们选择某一个视图后,在属性(Attributes)窗口 - inspector中,我们也可以单击属性值,然后进行修改:
goneMargin
对于标记View.GONE的视图,ConstraintLayout有特殊的处理机制。有这么一个情况,A距离容器的侧面有32dp边距,而B距离A有32dp,当将A标记为GONE,而B到容器侧面的边距为16dp:
标记为View.GONE的视图,通常是不显示的,并且不是布局本身的一部分。但是,在布局计算方面,其仍然是布局的一部分,不一样的是:
对于布局,它们的尺寸将被视为0(基本上,它们将被认为是一个点)
如果它约束其他控件,那么仍认为其存在,但任何margins视为0
这样就造成了上图所示的情况。假如即使A被标记为View.GONE,仍然想保持住在当前的位置,该怎么办?针对这种情况,ConstraintLayout专门设立了一个goneMargin,当约束视图的可见性为View.GONE时,可以使用不同的边距值:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
假如A的宽度为72dp,即使A被标记为View.GONE,B的位置仍不变,如下所示:
即使A被标记为View.GONE,计算时A仍然是布局的一部分,那么,我们应该这么计算B的左侧距离容器侧面的长度为:A距离容器的侧面的长度+A的宽度+B距A的长度,为136dp。该值应该就是goneMargin的值,那么在XML中,可以这么做:
...
...
当前情况是约束A视图的尺寸是已知的,如果约束视图的width/height类型为wrap_content时,就不能再xml中设置,需要在代码中,动态设置。对于如何动态设置约束,后续介绍…
带有链的线性视图组
在ConstraintLayout中,对线性试图组采用链的方式来处理,它们之间是彼此约束的。而,链又分为水平链和垂直链两种。例如,下图示出了两个彼此具有约束的视图,从而创建了水平链。
链头
在整个视图链中,尤其重要的是链头,其实际上是链中的第一个视图,即水平链中最左侧的视图和垂直链中的最顶端视图。
为什么说链头尤其重要呢?那是因为整体链的属性,在链头中设置,比如链的样式。
链的样式
所谓链的样式,就是链中的所有视图展开方式。在ConstraintLayout中允许以下几种方式展开链:
Spread:视图均匀分布(占用余量之后)。这是默认值。
Spread inside:第一个和最后一个视图贴在链的每一端的约束上,其余的都是均匀分布的。
Weighted:当链样式设置为Spread或Spread inside时,可以通过将一个或多个视图设置为“match constraints”(0dp)来填充剩余空间。默认情况下,空间在设置为“match constraints”的每个视图之间均匀分布,但可以使用layout_constraintHorizontal_weight和layout_constraintVertical_weight属性为每个视图分配一个分布的权重,其与线性布局中layout_weight类似。所以权重最大的观点得到最大的空间;具有相同权重的视图获得相同的空间量。
Packed:视图放置在一起(在边距计算之后)。然后,可以通过更改链的头部视图偏差来调整整个链条的偏差(左/右或上/下)
前面已经提到了,在链头中,设置属性layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle时,链的元素将根据指定的样式(默认为CHAIN_SPREAD)而排列。比如:
效果图:
快速创建链
前面,我们已经在XML中定义了一个水平链,只需要将链中的视图相互约束即可。在Layout Editor中,可以快速的创建一个链:
选择所有链中的视图
右键单击其中一个视图,然后选择Center Horizontally或Center Vertically,以分别创建水平链或垂直链
另外一方面,对于链的样式,是在XML中定义的,我们也可以在Layout Editor中修改:
选择链中的任何视图
单击视图下方的链接按钮来切换Spread,Spread inside和Packed
值得注意的是:
如果视图指定了链接约束边距,那么计算可用空间时,边距会考虑在内。在展开链时,边距将从自动可分配的空间中去除。
链只有在链的每个端部被约束到同一轴线上的不同对象时才正常工作
虽然,链的方向可以是垂直,的还可以是水平的,但是使用一个方向不会使所有视图在该方向上对齐。 因此,需要确保包含其他约束以实现链中每个视图的正确位置,例如对齐约束。
链的默认在可用空间中平均分配给元素。如果一个或多个元素设置MATCH_CONSTRAINT,那么它们将使用可用的剩余空间(在它们之间相等)。属性layout_constraintHorizontal_weight和layout_constraintVertical_weight用来标明可用剩余空间的分配比例。
由于ConstraintLayout并不支持ScrollLayout,尤其要注意链的空间分配,以避免视图被覆盖
到这里,ConstraintLayoput的基本使用以Layout Editor快速添加和修改约束已经讲解完了。
参考文档
User ConstraintLayout to design your Android Views
ConstraintLayout官方文档
使用 ConstraintLayout 构建自适应 UI
使用 Layout Editor 构建 UI