最近,看了郭神和鸿神关于ConstrainLayout的博客,写得很优秀,故模仿着也写下了这篇。
一、ConstraintLayout概述
ConstraintLayout, 即约束布局, 是Google在去年的I/O大会上重点宣传的一个功能。从支持力度而言, 将成为主流布局样式, 代替其他布局, 减少布局的层级, 优化渲染性能. 在新版Android Studio中, ConstraintLayout已替代RelativeLayout, 成为HelloWorld项目的默认布局。
ConstraintLayout是使用约束的方式来指定各个控件的位置和关系的,有点类似于RelativeLayout,但远比RelativeLayout要更强大。相比较于传统的Android编写xml文件,ConstraintLayout非常适合使用可视化的方式来编写界面。它的用法多是对控件进行拖拽。关于拖拽使用ConstraintLayout可以参见郭霖大神博客:Android新特性介绍,ConstraintLayout完全解析
但在开发中,敲代码会比拖拽来得更舒服,那是什么原因使得ConstraintLayout成为主流布局?
原因就在于性能优势。当界面越来越复杂,需要多层嵌套时,我们可以用RelativeLayout或者GridLayout来简化布局的深度,但也依然会伴随一些性能问题。而在界面绘制过程中,ConstraintLayout性能可以优于RelativeLayout达40%,层次更扁平,构建复杂布局更容易。
关于ConstraintLayout的性能优势可以参见:解析ConstraintLayout的性能优势
二、使用方式和属性说明
添加项目依赖:
compile 'com.android.support.constraint:constraint-layout:1.0.2
重要属性:
1、app:layout_constraintLeft_toLeftOf
先实现一个类似新闻列表的item
布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="140dp"
android:layout_height="86dp"
android:layout_marginLeft="12dp"
android:layout_marginTop="12dp"
android:background="#ffdd33" />
<TextView
android:id="@+id/tv2"
app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="12dp"
android:text="世界杯惊现“毒奶榜”,来自东方的神秘力量,位列前四的几只强队依次被淘汰"
android:textColor="#000000"
android:textSize="16dp" />
<TextView
app:layout_constraintBottom_toBottomOf="@id/tv1"
app:layout_constraintLeft_toRightOf="@id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="12dp"
android:text="8分钟前"
android:textColor="#333"
android:textSize="12dp" />
</android.support.constraint.ConstraintLayout>
tv1在父布局的左上角;tv2在tv1的右侧,tv2的右侧和父布局对其,tv2和tv1顶部对齐;
tv3在tv1的右侧,tv3和tv1底部对齐。
注意这里几个属性:
app:layout_constraintLeft_toLeftOf="parent":该控件的左侧与父布局对齐
app:layout_constraintLeft_toLeftOf="@id/viewB" :控件A与控件B左侧对齐
app:layout_constraintLeft_toRightOf="@id/viewB" :控件A在控件B的右侧
类似的属性有:
- layout_constraintRight_toLeftOf
- layout_constraintRight_toRightOf
- layout_constraintTop_toTopOf
- layout_constraintTop_toBottomOf
- layout_constraintBottom_toTopOf
- layout_constraintBottom_toBottomOf
- layout_constraintBaseline_toBaselineOf
这些属性和RelativeLayout很像,其实还是有区别的,举个栗子:
要使button2占满剩余宽度,在RelativeLayout中btn02需要设置layout_toRightOf="@id/id_btn01"和layout_alignParentRight="true",在ConstraintLayout中替换上面两个关系属性为:app:layout_constraintLeft_toRightOf="@id/id_btn01"和app:layout_constraintRight_toRightOf="parent",会发现:
button2宽度设为wrap时是上图,设为较大的某个固定值时是下图。
当宽度设为0dp时,button2才为占满剩余宽度。
原因:在ConstraintLayout中已经不支持MATCH_PARENT这个值了,你可以通过MATCH_CONSTRAINT配合约束实现类似的效果。在ConstraintLayout中0代表:MATCH_CONSTRAINT。
2、app:layout_constraintDimensionRatio
这个属性是设置宽高比,可以写成:
app:layout_constraintDimensionRatio="16:6"
app:layout_constraintDimensionRatio="W,16:6"
app:layout_constraintDimensionRatio="H,16:6"
举个栗子:
以前需要设置空间的宽高比,一般我们都需要在代码中显式的去操作,现在constraintLayout一个属性就解决了。
<TextView
android:id="@+id/banner"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#765"
android:gravity="center"
android:text="Banner"
app:layout_constraintDimensionRatio="H,16:6"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
3、app:layout_constraintHorizontal_weight
当我们需要3个控件均分宽度时,在ConstraintLayout中可以通过属性这样使用:
<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" />
也能通过属性 app:layout_constraintHorizontal_weight 控制单个元素的占据比例
4、app:layout_constraintHorizontal_chainStyle
如上,3个tab两两设置了依赖,横向的相当于组成了一个链(Chains)。在这个链的最左侧的元素成为链头,我们可以在其身上设置一些属性,来决定这个链的展示效果:
该属性为 layout_constraintHorizontal_chainStyle,其取值可以为:spread,packed,spread_inside
几种组合的效果如下:
5、app:layout_constraintHorizontal_bias
当我们需要添加一个浮动按钮时,正常情况我们可以通过margin来设置与右侧与底部的距离。
在ConstraintLayout中我们可以通过属性app:layout_constraintHorizontal_bias和layout_constraintVertical_bias来设置上下两侧间隙比例。
举个栗子:
<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" />
6、app:layout_constraintGuide_begin
Guideline是个比较特殊的类,主要用于辅助布局,即类似为辅助线,横向的、纵向的。辅助线是不会显示到界面上的
比如:
layout_constraintGuide_begin = "30dp",距离顶部30dp的地方有个辅助线,根据orientation来决定是横向还是纵向
layout_constraintGuide_end ="30dp",距离底部30dp的地方有个辅助线,根据orientation来决定是横向还是纵向
layout_constraintGuide_percent = "0.8",距离顶部80%的地方有个辅助线,根据orientation来决定是横向还是纵向