*本篇文章已受权微信公众号 guolin_blog (郭霖)独家发布android
简书地址 www.jianshu.com/p/502127a49…api
本文是基于constraint-layout:1.1.2bash
在之前,android是使用布局如LinearLayout 、RelativeLayout等来构建页面,但这些布局使用起来很麻烦,而且常常须要一层一层嵌套,写一个简单的页面就须要费很大的劲。因此在16年I/O大会上,google发布了全新的布局-ConstraintLayout,其余布局和ConstraintLayout比起来,根本就没有存在的必要了... ConstraintLayout具备如下优点:微信
较高的性能优点。 布局嵌套层次越高,性能开销越大。而使用ConstraintLayout,常常就一层嵌套就搞定了,因此其性能要好不少。 详细的性能分析可参见:解析ConstraintLayout的性能优点app
完美的屏幕适配 ConstraintLayout的大小、距离均可以使用比例来设置,因此其适配性更好。编辑器
书写简单ide
可视化编辑。 ConstraintLayout也有十分方便完善的可视化编辑器,不用写xml也基本上能实现大部分功能。但我的仍是比较喜欢写xml,因此本篇文章主要介绍如何使用代码控制。若是想看如何使用可视化编辑器,能够参考郭霖大神的这篇文章布局
引入:
api 'com.android.support.constraint:constraint-layout:1.1.2'
性能
肯定位置的属性提供了下面13个属性,其实本质上都是同样的,看名字应该基本上都知道怎么用了(就是哪一条边和哪一条边对齐)动画
来看个例子:
实现上述UI的相关代码以下:
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
....
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="A" />
<Button
android:id="@+id/b"
....
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintTop_toTopOf="@id/a"
android:text="B" />
<Button
android:id="@+id/c"
....
app:layout_constraintLeft_toLeftOf="@id/a"
app:layout_constraintTop_toBottomOf="@id/a"
android:text="C" />
<Button
android:id="@+id/d"
....
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintTop_toTopOf="@id/c"
android:text="D" />
</android.support.constraint.ConstraintLayout>
复制代码
从中能够看到,
app:layout_constraintLeft_toRightOf="@id/a"
,C位于A的下边,则使用app:layout_constraintTop_toBottomOf="@id/a"
对于一个View的边界界定,官方给了下面这张图:
设置margin仍是继续用之前的属性layout_margin*
。 不过须要注意,要使margin生效,必须具备对应方向的layout_constraint*
,不然margin不生效.
###3. 关于view gone 假如如今有以下布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
...
android:layout_marginLeft="100dp"
android:layout_marginTop="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/b"
...
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintTop_toTopOf="@id/a"
/>
<Button
android:id="@+id/c"
....
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
app:layout_constraintLeft_toRightOf="@id/b"
app:layout_constraintTop_toTopOf="@id/b" />
</android.support.constraint.ConstraintLayout>
复制代码
考虑一个问题,若是B动态设为gone了,C会怎么显示呢? 真实状况以下:
layout_goneMargin*="xdp"
,意思是好比当constrainleft的锚点gone时,layout_goneMarginLeft将生效。但由于这个只能设置固定的距离,我的感受灵活性不是很高。一个view如何设置为居中呢?若是查找属性,会发现并无如RelativeLayout相似的layout_centerVertical属性,那如何设置居中呢?constraint的思想很巧妙。 根据第一节的知识,你们知道若是设置app:layout_constraintLeft_toLeftOf="parent"
,则view会贴着父view的左边,设置app:layout_constraintRight_toRightOf="parent"
则会贴着右边,那若是两个都设置,效果会怎样呢?
bias即偏移量,他们的取值范围从0~1,0即挨着左边,1是挨着右边,因此要使处于1/3处,能够设置以下属性app:layout_constraintHorizontal_bias="0.33"
,效果图以下:
spread
,默认值,意思是占用全部的符合约束的空间
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
android:layout_width="0dp"
...
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
复制代码
能够看到layout_width为0dp,实际的效果则是宽度和约束同样,左右两边的留白是margin的效果。
percent
,意思是按照父布局的百分比设置,须要layout_constraintWidth_percent
设置百分比例
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout >
<android.support.constraint.ConstraintLayout
android:layout_width="300dp"
android:layout_height="400dp"
app:layout_constraintHorizontal_bias="0.3"
>
<Button
android:id="@+id/a"
android:layout_width="0dp"
...
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.4" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
复制代码
A的宽度设为0.4,则其宽度为父布局的0.4倍。另外,设置了layout_constraintWidth_percent属性,能够不用指定layout_constraintWidth_default,他会自动设置为percent
wrap
,意思匹配内容大小但不超过约束限制,注意和直接指定宽度为wrap_content的区别就是不超过约束限制,以下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
...
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/c"
...
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/b"
android:layout_width="0dp"
...
app:layout_constraintWidth_default="wrap"
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintRight_toLeftOf="@id/c"/>
<Button
android:id="@+id/d"
android:layout_width="wrap_content"
...
app:layout_constraintTop_toBottomOf="@id/b"
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintRight_toLeftOf="@id/c"/>
</android.support.constraint.ConstraintLayout>
复制代码
能够看到虽然文字很长,但第一行的绿色button宽度达到约束时,就不在增长,而第二行的button显示了完整的内容,超过约束的限制。 在1.1上 对于wrap_content会超过约束限制,谷歌又新增了以下属性
设置为true也能够限制内容不超过约束(这样感受layout_constraintWidth_default这个属性已经没什么用了)
layout_constraintDimensionRatio
,即宽和高成必定的比例,其值能够是"width:height"的形式,也能够是width/height的值。该属性生效的前提:宽和高其中有一项为0dp,有constraint。下面按照有几个0dp来分别介绍下:###6. 链 如图,在一个水平或者竖直方向上,一排view两两互相约束,即为链
layout_constraintHorizontal_chainStyle
来控制链的分布形式
spread 默认模式,分布样式如上图
spread_inside 如图,和spread的区别是没算两端的约束
packed 全部元素挤在中间,也能够配合使用bias来改变位置偏移
能够看出,链与LinearLayout效果大体同样。和LinearLayout同样,链也可使用layout_constraintHorizontal_weight
,来分割剩余空间。但又和 android:layout_weight不太同样,不同的地方以下:
以下面的示例:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
...>
<LinearLayout
...
android:orientation="horizontal">
<Button
android:layout_width="10dp"
android:layout_height="50dp"
android:layout_weight="1"
... />
<Button
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
... />
<Button
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
... />
</LinearLayout>
<android.support.constraint.ConstraintLayout
....>
<Button
android:id="@+id/a"
android:layout_width="10dp"
android:layout_height="50dp"
....
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/b" />
<Button
android:id="@+id/b"
android:layout_width="wrap_content"
android:layout_height="50dp"
....
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/a"
app:layout_constraintRight_toLeftOf="@id/c" />
<Button
android:id="@+id/c"
android:layout_width="0dp"
android:layout_height="50dp"
...
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/b"
app:layout_constraintRight_toRightOf="parent" />
/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
复制代码
能够看出,LinearLayout和ConstraintLayout虽然三个子view的layout_width值是同样的,weight也都设置了1,但效果彻底不同
ConstraintLayout还提供了一种比较炫酷的圆形布局,这是以往的布局所作不到的。涉及到的属性也很简单,就下面三个:
示例以下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
...>
<Button
android:id="@+id/a"
...
/>
<Button
android:id="@+id/b"
...
app:layout_constraintCircle="@id/a"
app:layout_constraintCircleAngle="300"
app:layout_constraintCircleRadius="100dp" />
<Button
android:id="@+id/c"
...
app:layout_constraintCircle="@id/a"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="200dp" />
/>
</android.support.constraint.ConstraintLayout>
复制代码
#3、辅助组件
除了
ConstraintLayout
自身属性以外,谷歌还提供了不少辅助布局(只是在布局中起辅助做用,并不会在界面真正显示),来使ConstraintLayout
的功能更增强大。下面,咱们就一一来了解下这些布局
即参考线的意思,有水平参考线和竖直参考线两种。他的做用就像是一个虚拟的参考线,只是用来方便其余View以他为锚点来布局。 如上一篇所了解到的,ConstraintLayout 的定位原则就是一个View参考其余View的相对布局,若是有的时候当前布局没有合适的参考View,而建一个专门用于定位的View又会过重,这种状况正是GuideLine的用武之地。 例如:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<android.support.constraint.Guideline
android:id="@+id/guideline"
...
android:orientation="vertical"
app:layout_constraintGuide_percent="0.33" />
<android.support.constraint.Guideline
android:id="@+id/guideline2"
...
android:orientation="horizontal"
app:layout_constraintGuide_begin="130dp" />
<Button
...
app:layout_constraintLeft_toLeftOf="@id/guideline"
app:layout_constraintTop_toTopOf="@id/guideline2" />
</android.support.constraint.ConstraintLayout>
复制代码
能够看到我分别添加了一个水平参考线和竖直参考线,以后的Button的布局就参考与这两个参考线,而在布局中并不会显示。 Guideline
的大部分的属性如layout_width都是不会生效的,而他的位置的肯定是由下面三个属性之一来肯定的:
Group是一个能够同时控制多个view 可见性的虚拟View。 例如:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<android.support.constraint.Group
...
android:visibility="invisible"
app:constraint_referenced_ids="a,c" />
<android.support.constraint.Group
...
android:visibility="visible"
app:constraint_referenced_ids="b,d" />
<Button
android:id="@+id/a"
... />
<Button
android:id="@+id/b"
... />
<Button
android:id="@+id/c"
... />
<Button
android:id="@+id/d"
.../>
</android.support.constraint.ConstraintLayout>
复制代码
能够看到,第一个Group经过app:constraint_referenced_ids
指定了a、c两个控件,这样当该Group可见性为invisible时,a、c的可见性都会变为invisible,为gone则都为gone。因此Group很适合处理有网无网之类的场景,再也不须要像以前那样一个一个view控制可见性,经过Group就能够统一处理了。 Group有一些注意事项:
app:constraint_referenced_ids
里直接写的是id的字符串,初始化后会经过getIdentifier
来反射查找叫该名字的id。因此若是你的项目用了相似AndResGuard的混淆id名字的功能,切记不要混淆app:constraint_referenced_ids
里的id,不然在release版本就会因找不到该id而失效。或者也能够经过代码setReferencedIds
来设置id。占位布局。他本身自己不会绘制任何内容,但他能够经过设置app:content="id"
,将id View的内容绘制到本身的位置上,而原id的 View就像gone了同样。 以下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="30dp"
...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/b"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
...
app:layout_constraintLeft_toRightOf="@+id/a"
app:layout_constraintTop_toTopOf="@+id/a" />
<android.support.constraint.Placeholder
android:id="@+id/place"
android:layout_width="200dp"
android:layout_height="200dp"
app:content="@+id/a"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
...
app:layout_constraintBottom_toBottomOf="@+id/place"
app:layout_constraintLeft_toRightOf="@+id/place" />
</android.support.constraint.ConstraintLayout>
复制代码
效果如图:
能够看到,本来B是位于A的右边而且顶部对齐的,但由于A被Placeholder引用,使A 至关于Gone了。而Placeholder的位置则显示了A的内容,而且大小也和A相符,Placeholder的大小设置并无生效。 大概总结能够认为,Placeholder引用A后的效果是,本来位置的A gone,本来位置的Placeholder变为Placeholder的约束属性+A的内容属性。另外,Placeholder也支持使用代码setContentId
动态的修改设置内容。
关于Placeholder的应用场景,网上其余人也都列出了一些例子:好比能够做为位置模板,引入后只须要写内容view;使用代码动态改变内容,结合TransitionManager能够作一些有趣的过分动画等。
屏障,一个虚拟View。他主要解决下面遇到的问题:
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"//end,left,right,top,bottom
app:constraint_referenced_ids="text1,text2" />
复制代码
则Barrier始终位于text1,text2两个View最大宽度的右边,示意图以下:
这里基本的用法就讲完了。 下面再考虑一个状况,假若有以下的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...>
<Button
android:id="@+id/a"
...
android:layout_marginTop="20dp"
/>
<Button
android:id="@+id/b"
...
android:layout_marginTop="40dp"
/>
<android.support.constraint.Barrier
android:id="@+id/barrier"
...
app:barrierDirection="top"
app:constraint_referenced_ids="a,b" />
<Button
android:id="@+id/c"
...
app:layout_constraintTop_toTopOf="@+id/barrier" />
</android.support.constraint.ConstraintLayout>
复制代码
目前Button C和Button a、b的最上值对齐,没有问题。但若是a Gone了呢?效果以下:
barrierAllowsGoneWidgets
,设为false后,就不在关注Gone的View了,效果以下:
##4、结束 本篇已基本上介绍完ConstraintLayout全部的属性了(除了代码写布局的ConstraintSet类)。在2018.8.9号,谷歌又发布了2.0.0-alpha2版本,里面加入了许多好玩的新特性,相信ConstraintLayout以后会愈来愈强大。