Android ConstraintLayout
在升级Android Studio 2.3之后,发现再创建Activity生成的布局都是以ConstraintLayout作为根布局,浏览了一下Google官方力推的ConstraintLayout后,觉得这个布局很实用。
平台支持
- ContraintLayout 最低兼容Android 2.3
- 目前Android Studio 默认使用ConstraintLayout作为布局文件的根布局
- 想要使用ConstraiLayout,需在项目中添加
com.android.support.constraint:constraint-layout:xxx版本号
基础使用
ContraintLayout 翻译成中文是约束布局,在整个使用中,对于组件的约束很明显。
ConstraintLayout定义
ConstraintLayout可以灵活控制子控件的位置和大小的新布局。这个布局可以实现布局最大程度的扁平化
为什么要使用ConstraintLayout
我们知道项目中的布局嵌套问题对我们的项目性能有着不小的威胁。布局能实现扁平化的话会让软件性能得到很大的提升。所以我们在开发中应当尽量避免布局嵌套现象
- ConstraintLayout 可以在不嵌套view group的情况下实现非常庞大、复杂的布局。实现扁平化
- Contraint Layout同时具有RelativeLayout和LinearLayout的优点和特性。
- 使用ContraintLayout来布局时性能要比其他布局方式高
对比LinearLayout和RelativeLayout
在Android传统的布局 LinearLayout和RelativeLayout布局中,我们知道,在measure过程中 RelativeLayout是measure两次的。而LinearLayout是正常情况下只会measure一次,非正常情况下,在使用LinearLayout中的weight属性的控件做第二次measure。综合来看使用LinearLayout性能上来说比RelativeLayout好些。所以系统的decorview也就是使用的LinearLayout,上面是标题栏下面是内容ContentView。
效果图
我们想要实现一个左边是一个图片控件,右边是一个上下的标题
就是普通的item的布局,我们的布局文件是
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".basicfunc.home.view.AppHomeActivity">
<TextView
android:id="@+id/tv0"
android:layout_width="140dp"
android:layout_height="80dp"
android:background="@android:color/holo_red_light"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/tv1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/tv0"
app:layout_constraintTop_toTopOf="@id/tv0"
android:layout_marginLeft="8dp"
android:text="主标题主标题主标题主标题主标题主标题主标题"
android:textSize="16sp" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv1"
app:layout_constraintLeft_toRightOf="@id/tv0"
android:layout_marginLeft="8dp"
android:text="副标题副标题副标题副标题副标题副标题"
android:textSize="12sp" />
</android.support.constraint.ConstraintLayout>
上面的布局,我们看到了几个没有见过的属性,我们来介绍一下
首先是tv0:
- app:layout_constraintLeft_toLeftOf = "parent"
从字面上看 是“约束控件的左边在目标控件的左边” 目标为父布局的时候,就是父布局对齐,当我们希望控件A与控件B左侧对齐时,我们可以使用该属性
app:layout_constraintLeft_toLeftOf = "@id/viewB"
- 类似的还有一个相似的属性为
app:layout_constraintLeft_toRightOf
即当前属性的左侧在谁的右侧,我们希望控件A在控件B的右侧时可以设置
app:layout_constraintLeft_toRightOf="@id/viewB"
类似的属性
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
和Relative的差异
Relative
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"> <Button
android:id="@+id/id_btn01"
android:layout_width="100dp"
android:text="Btn01"
android:layout_height="wrap_content" /> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/id_btn01"
android:text="Btn02"
android:layout_alignParentRight="true"
/> </RelativeLayout>
RL效果
ConstraintLayout
layout_toRightOf="@id/id_btn01",layout_alignParentRight="true"
分别替换为:
app:layout_constraintLeft_toRightOf="@id/id_btn01",app:layout_constraintRight_toRightOf="parent"
ConstraintLayout效果
我们发现布局效果不一致
在当控件有自己设置的宽度,例如 wrap_content,固定值时,我们为控件添加的都是约束"Constrain",这个约束有点像作用力一样去挤压这个控件,但是不会改变控件的尺寸,很明显的RelativeLayout不是这样
但是,上面的这种情况下,如果我们使用约束 约束btn2在 btn1的同时 又与parent右侧对其,当两个约束同时生效的时候,btn02会居中。会造成这个作用力两端一样大。
这是为什么?如何能达到btn2将占据剩下的距离
当我们将btn2的宽度设置为0
这里我们明白了。在ContraintLayout中 0的意义:代表MATCH_CONSTRAINT
在ContraintLayout中已经不再支持MATCH_PARENT这个值了,可以通过MATCH_CONSTRAINT来实现效果
现在我们再来看看ContraintLayout强大的效果
我们在我们的item上再添加一个TextView 宽度为整个屏幕 长宽比为16:9
在布局中设置长宽比是非常难的,我们一般需要再代码中去计算。如果使用了ConstraintLayout布局中就可以支持
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".basicfunc.home.view.AppHomeActivity">
<TextView
android:id="@+id/banner"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_green_light"
android:text="banner"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
/>
<TextView
android:id="@+id/tv0"
android:layout_width="140dp"
android:layout_height="80dp"
android:background="@android:color/holo_red_light"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/banner"
/>
....
宽高比效果
这个宽高比还支持这样的写法:
app:layout_constraintDimensionRatio="W,16:6"
app:layout_constraintDimensionRatio="H,16:6"
增加tab
<TextView
android:id="@+id/tab1"
android:layout_width="0dp"
android:layout_height="30dp"
android:background="#f67"
android:gravity="center"
android:text="Tab1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tab2" /> <TextView
android:id="@+id/tab2"
android:layout_width="0dp"
android:layout_height="30dp"
android:background="#A67"
android:gravity="center"
android:text="Tab2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tab1"
app:layout_constraintRight_toLeftOf="@+id/tab3" /> <TextView
android:id="@+id/tab3"
android:layout_width="0dp"
android:layout_height="30dp"
android:background="#767"
android:gravity="center"
android:text="Tab3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tab2"
app:layout_constraintRight_toRightOf="parent" />
tab
在这样的效果中 我们增加了3个TextView来冒充tab,横向的依赖 3个tab两两设置约束(即你在我们的左边 我再你的右边)
这种效果对于LinearLayout也能实现,但是ConstraintLayout也有设置权重weight的属性
app:layout_constraintHorizontal_weight
如果我们将权重设置成了2:1:1
图片.png
我们已经见过一种效果了,即按照weight等分,可以成为weighted chain。设置条件为:
chainStyle=”spread”,所有控件宽度设置为match_constraint,因为默认就是spread,所以我们没有显示设置。
其取值还可以为:
* packed
* spread_inside
1.spread + 宽度非0
图片.png
2.spread + 宽度为0 且通过weight控制分配比例(等分)
3.spread_inside+ 宽度非0
图片.png
4 packed+宽度非0
图片.png 官网解释图片
bias属性
再没有bias属性的时候,我们刚才说了 ConstraintLayout作用于控件两侧的力量是一样大的,我们可以通过bias设置偏向某个方向的作用力
这个属性可以用于约束之前,控制两侧的“拉力”
<android.support.constraint.ConstraintLayout
...
tools:context="com.zhy.constrantlayout_learn.MainActivity"> <TextView
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#612"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.9" /> </....>
bias:表示水平设置两侧间隙比例为90%与10% 通过这个我们可以实现类似于margin的效果
20170917222509804.jpg
最后
由于好久没有看Android了,对于一些新特性(ps:现在可能都不叫新特性了)还是不是很了解,打算通过做一个项目来学习一下,在学习过程中由于水平太菜,参考了很多大神的博客,向大神致敬:
鸿洋大神:https://blog.csdn.net/lmj623565791/article/details/78011599
掘金专题:http://blog.coderclock.com/2017/04/09/android/android-constraintlayout/