ConstraintLayout,让布局更优雅。html
上图是网易100分的选课首页,在Banner图的下部是推荐类目模块,其中数学、语言、小低和小高分别是推荐类目Item。可见每一个类目的子类目个数是不肯定的,根据个数的不一样,子类目的排列方式也不同。android
如今咱们来实现Item的布局。若是用LinearLayout、RelativeLayout和FrameLayout去实现Item布局,我目前想到的最低也须要两层布局。以下所示:git
<Relative>
<ImageView />
<TextView />
<LinearLayout>
<TextView />
<TextView />
<TextView />
</LinearLayout>
<LinearLayout>
<TextView />
<TextView />
</LinearLayout>
</Relative>
复制代码
能够发现没有一种布局容器是能够单靠本身搞定这个布局的,须要嵌套不一样布局。这样布局层级增长,布局计算时间也加长了。这些都是传统布局存在的问题,归纳起来有如下三点:github
正是因为目前布局容器存在的问题,咱们须要寻找一种能够解决这些问题的布局容器。正好,ConstraintLayout能够。编程
ConstraintLayout,中文称约束布局,在2016年Google I/O大会时提出,2017年2月发布正式版,目前稳定版本为1.0.2。约束布局做为Google从此主推的布局样式,能够彻底替代其余布局,下降页面布局层级,提高页面渲染性能。bash
ConstraintLayout支持最低Android Studio版本是2.2,可是有些属性在2.2的布局编辑器上不支持编辑,如比例和baseline等约束。因此推荐使用2.3的版本,固然3.0的版本那就更好了。要使用ConstraintLayout,须要在项目中进行以下配置:app
repositories {
maven {
url 'https://maven.google.com'
}
}
复制代码
dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
复制代码
按照上述配置好环境后,咱们就能够在项目中使用ConstraintLayout了。有两种方式使用:maven
layout转换的方式使用编辑器
首先,打开一个非ConstraintLayout的布局文件,切换到Design Tab
ide
在Component Tree窗口,选中要转换的layout文件根布局,点击右键,而后选择Convert layout to ConstraintLayout
直接新建一个layout文件使用
经过以下方式引入约束布局:
<android.support.constraint.ConstraintLayout
/>
复制代码
ConstraintLayout的布局属性,乍一看有不少,其实能够分为8个部分,下面一一介绍。
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
复制代码
以上这些属性,用于设置一个控件相对于其余控件、Guideline或者父容器的位置。以layout_constraintLeft_toLeftOf
为例,其中layout_
部分是固定格式,主要的信息包含在下面两部分:
constraintLeft
表示对当前控件的左边进行约束设置。XXX
指定被依赖对象用于参考的属性。如toLeftOf="parent"
:表示当前控件相对于父容器的左边进行约束设置。ConstraintLayout的相对位置布局比较灵活,相比于RelativeLayout,ConstraintLayout能够经过layout_constraintBaseline_toBaselineOf
设置两个控件之间的文字相对于baseline对齐。一个布局效果的例子,以下所示:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_relative_position"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.RelativePositionActivity">
<Button
android:id="@+id/btn_A"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<Button
android:text="在A下方,与A左对齐"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
android:layout_marginTop="32dp"
/>
<Button
android:text="在A上方,与A居中对齐"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
app:layout_constraintRight_toRightOf="@id/btn_A"
android:layout_marginBottom="32dp"
/>
<Button
android:text="baseline对齐"
android:layout_width="wrap_content"
android:layout_height="80dp"
app:layout_constraintBaseline_toBaselineOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="8dp"
android:gravity="bottom"
/>
<Button
android:text="水平居中对齐"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:gravity="bottom"
app:layout_constraintTop_toTopOf="@id/btn_A"
app:layout_constraintBottom_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toRightOf="@id/btn_A"
android:layout_marginLeft="16dp"
/>
</android.support.constraint.ConstraintLayout>
复制代码
在ConstraintLayout中,控件除了能够设置普通的边距属性,还能够设置当控件依赖的控件GONE以后的边距属性。即咱们能够理解能够根据被依赖控件是否GONE的状态,设置两种边距值。分别经过以下属性进行设置:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
复制代码
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
复制代码
这种特性,能够比较方便实现一些特定的需求,且无需代码中进行额外设置。如B控件依赖A,A距离父容器左边20dp,B在A右边,距离A为20dp。需求当A设置为GONE以后,B距离父容器左边60dp。这在ConstraintLayout中实现起来就很简单,对B同时设置以下属性便可:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_margin"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.MarginActivity">
<Button
android:id="@+id/btn_a"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="100dp"
/>
<Button
android:text="B"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn_a"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="20dp"
app:layout_goneMarginLeft="60dp"
android:layout_marginTop="100dp"
/>
</android.support.constraint.ConstraintLayout>
复制代码
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent 复制代码
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
复制代码
例子:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_center_position"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.CenterPositionActivity">
<Button
android:text="水平居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:text="垂直居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<Button
android:text="水平垂直居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
复制代码
在设置控件的居中属性以后,经过偏移属性能够设置让控件更偏向于依赖控件的某一方,偏移设置为0~1之间的值。相应属性:
layout_constraintHorizontal_bias // 水平偏移
layout_constraintVertical_bias // 垂直偏移
复制代码
例子:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_bias"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.BiasActivity">
<Button
android:text="水平偏移30%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3"
/>
<Button
android:text="垂直偏移30%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.3"
/>
<Button
android:text="水平垂直偏移70%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.7"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.7"
/>
</android.support.constraint.ConstraintLayout>
复制代码
可见性这个属性你们应该很熟悉,可是约束布局的可见性属性和其它布局相比,存在如下区别:
当控件设为GONE时,被认为尺寸为0。能够理解为布局上的一个点。
若GONE的控件对其它控件有约束,则约束保留并生效,但全部的边距(margin)会清零。
wrap_content
,根据内容计算合适大小match_parent
,填充满父布局,此时设置的约束都不生效了。(早以前的约束布局版本貌似不容许在其子view中使用match_parent属性,可是我写文章的时候发现也是能够用上去的)layout_constraintWidth_min
和layout_constraintHeight_min
:设置最小值
layout_constraintWidth_max
和layout_constraintHeight_max
:设置最大值
layout_constraintWidth_percent
和layout_constraintHeight_percent
:设置控件相对于父容器的百分比大小(1.1.0开始支持)。使用以前须要先设置为百分比模式,而后设置设置宽高值为0~1之间。
设置为百分比模式的属性:
复制代码
app:layout_constraintWidth_default="percent" app:layout_constraintHeight_default="percent" ```
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
复制代码
看个具体例子:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_dimen"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.DimenActivity">
<Button
android:id="@+id/btn_1"
android:text="minWidth设置为200dp"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:minWidth="200dp"
/>
<Button
android:id="@+id/btn_2"
android:text="设置为MATCH_CONSTRAINT"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:id="@+id/btn_3"
android:textAllCaps="false"
android:text="layout_constrainedWidth开启"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="300dp"
/>
<Button
android:id="@+id/btn_4"
android:textAllCaps="false"
android:text="layout_constrainedWidth关闭"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_min="300dp"
/>
<Button
android:id="@+id/btn_5"
android:textAllCaps="false"
android:text="宽50%高30%布局"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/btn_4"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintHeight_default="percent"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintHeight_percent="0.3"
/>
</android.support.constraint.ConstraintLayout>
复制代码
控件能够定义两个尺寸之间的比例,目前支持宽高比。 前提条件是至少有一个尺寸设置为0dp,而后经过layout_constraintDimentionRatio
属性设置宽高比。设置方式有如下几种:
若是宽高都设置为0dp,也能够用ratio设置。这种状况下控件会在知足比例 约束的条件下,尽量填满父布局。
下面看个例子:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.RatioActivity">
<Button
android:id="@+id/btn_1"
android:text="宽高比设置为2:1"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:id="@+id/btn_2"
android:text="宽高都设置为0dp,高宽比是16:9"
android:textAllCaps="false"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintTop_toBottomOf="@id/btn_1" />
</android.support.constraint.ConstraintLayout>
复制代码
链这个概念是约束布局新提出的,它提供了在一个维度(水平或者垂直),管理一组控件的方式。
多个view在同一个方向上双向引用。以下图所示:水平方向A、B、C,A位于B左边,B位于A右边,他们就是一对双向引用。同理B和C也是。
双向引用布局代码以下所示。A经过app:layout_constraintRight_toLeftOf="@+id/btn_2"
引用右边的B,B经过app:layout_constraintLeft_toRightOf="@+id/btn_1"
引用A。
<Button
android:id="@+id/btn_1"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
<Button
android:id="@+id/btn_2"
android:text="B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_spread"
app:layout_constraintLeft_toRightOf="@+id/btn_1"
app:layout_constraintRight_toLeftOf="@+id/btn_3"
/>
...
复制代码
最左边或最上面的控件,链的属性由链头控制。
经过layout_constraintHorizontal_chainStyle
和layout_constraintVertical_chainStyle
在链的第一个元素上设置。默认spread样式。如上所示,A做为链头,设置了chainStyle:app:layout_constraintHorizontal_chainStyle="spread_inside"
。
几种链的样式以下图所示:
链的布局代码比较多,你们能够看demo。主要是经过修改链头的chainStyle样式改变链的类型。
能够理解为布局辅助线,用于布局辅助,不在设备上显示。
有垂直和水平两个方向(android:orientation=“vertical/horizontal”)
有三种放置Guideline的方式:
layout_constraintGuide_begin
)layout_constraintGuide_end
)layout_constraintGuide_percent
)看例子:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_guideline"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="zr.com.constraintdemo.GuidelineActivity">
<!-- 垂直Guideline -->
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
app:layout_constraintGuide_percent="0.5"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:text="GuideLine左边"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_1"
app:layout_constraintRight_toLeftOf="@+id/guideline"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:text="GuideLine右边"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_2"
app:layout_constraintLeft_toRightOf="@+id/guideline"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
/>
<!-- 水平Guideline -->
<android.support.constraint.Guideline
android:id="@+id/h_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintGuide_begin="200dp"
/>
<Button
android:text="Guideline上面"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/h_guideline"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:text="Guideline下面"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/h_guideline"
app:layout_constraintLeft_toLeftOf="parent"
/>
</android.support.constraint.ConstraintLayout>
复制代码
经过ConstraintSet,容许在代码中进行约束设置,进行布局变换。(API 19及以上支持trasmition动画)
建立ConstraintSet对象的几种方式:
c = new ConstraintSet();
c.connect(....);
复制代码
c.clone(context, R.layout.layout1);
复制代码
c.clone(clayout);
复制代码
布局变化开启平滑动画的方式:
TransitionManager.beginDelayedTransition(constraintLayout);
复制代码
其中参数constraintLayout表示动画做用的约束布局对象。
看个例子:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 4.4以上开启布局切换动画
TransitionManager.beginDelayedTransition(constraintLayout);
// 清空margin
applyConstraintSet.setMargin(R.id.btn_1, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_1, ConstraintSet.END, 0);
applyConstraintSet.setMargin(R.id.btn_2, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_2, ConstraintSet.END, 0);
applyConstraintSet.setMargin(R.id.btn_3, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_3, ConstraintSet.END, 0);
// 所有相对于父容器居中
applyConstraintSet.centerHorizontally(R.id.btn_1, R.id.activity_constraint_set);
applyConstraintSet.centerHorizontally(R.id.btn_2, R.id.activity_constraint_set);
applyConstraintSet.centerHorizontally(R.id.btn_3, R.id.activity_constraint_set);
applyConstraintSet.applyTo(constraintLayout);
}
复制代码
看下在4.4系统以上动画的一个效果:
更多ConstraintSet例子,推荐看这篇文章
说了这么多,那么约束布局用起来到底怎么样呢?下面咱们来实践下:
咱们先来分析下类目Item,能够将类目Item分为两个部分:父类目和子类目两部分。父类目包括图片icon和文字描述。子类目包含根据个数布局可变的按钮。很明显,父类目经过约束布局的相对位置约束设置能够实现。子类目中的子控件,能够以父布局中的某个控件和子类目中其余子控件为参照物(依赖参照对象)实现布局。总共放置两排的按钮,第一排3个,第二排2个,宽度设置为MATH_CONSTRAINT。而后在代码中根据子类目的个数,设置相应按钮的可见性便可实现Item根据子类目个数展现不一样布局的效果。
布局XML:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:paddingTop="7.5dp"
android:paddingBottom="7.5dp"
android:paddingLeft="12.5dp"
android:paddingRight="12.5dp"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@mipmap/ic_launcher"
/>
<TextView
android:id="@+id/tv_parent_category_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="少儿编程"
android:textSize="15sp"
android:textColor="#333333"
app:layout_constraintBottom_toBottomOf="@id/img_icon"
app:layout_constraintLeft_toRightOf="@id/img_icon"
app:layout_constraintTop_toTopOf="@id/img_icon" />
<!-- 子类目布局开始 -->
<Button
android:id="@+id/btn_one"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:text="A"
app:layout_constraintTop_toBottomOf="@id/img_icon"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_two" />
<Button
android:id="@+id/btn_two"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/btn_one"
app:layout_constraintRight_toLeftOf="@+id/btn_three"
app:layout_constraintTop_toTopOf="@id/btn_one" />
<Button
android:id="@+id/btn_three"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/btn_two"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_two" />
<!-- 第二排 -->
<Button
android:id="@+id/btn_four"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:text="D"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_five"
app:layout_constraintTop_toBottomOf="@id/btn_one" />
<Button
android:id="@+id/btn_five"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="E"
app:layout_constraintLeft_toRightOf="@+id/btn_four"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_four" />
</android.support.constraint.ConstraintLayout>
复制代码
实现效果:
要求:图片宽高比16:9,图片宽度固定110dp。
分析:宽高比16:9,须要比例布局;其余都是一些位置关系,用约束布局相对位置的一些约束能够实现。
具体实现:
布局XML:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
<ImageView
android:id="@+id/iv_course"
android:layout_width="110dp"
android:layout_height="0dp"
android:scaleType="fitXY"
android:src="@mipmap/test"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_course_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="15dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#333333"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/iv_course"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_course"
tools:text="六年级单元过关检测六年级单元过关检测六年级单元过关检测" />
<TextView
android:id="@+id/tv_signature"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#666666"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_course_name"
tools:text="签名" />
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#666666"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signature"
tools:text="内容内容内容内容内容内容内容内容内容内容" />
<TextView
android:id="@+id/tv_current_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:maxLines="1"
android:textColor="#f6454a"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintTop_toBottomOf="@id/tv_content"
tools:text="¥ 480" />
<TextView
android:id="@+id/tv_origin_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:maxLines="1"
android:textColor="#999999"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/tv_current_price"
app:layout_constraintLeft_toRightOf="@id/tv_current_price"
tools:text="¥ 1480" />
</android.support.constraint.ConstraintLayout>
复制代码
实现截图:
要求:图片宽度占整个布局30%,宽高比16:9。
分析:看到30%,首先考虑的是百分比布局,可是图片右边的view较多,每一个都是设置一边百分比,实在是麻烦。所以,能够考虑使用Guideline,设置Guideline垂直,并距离父容器左边30%的距离,以后布局经过Guideline设置约束便可。
布局XML:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/iv_course"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY"
android:src="@mipmap/test"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
...
</android.support.constraint.ConstraintLayout>
复制代码
要求:在以前基础上,底部加一根横线用于分隔,要求线与上面最近的控件距离是15dp。
分析:因为文字内容是可变的,当文字内容多的时候,线可能距离文字近;若文字很少,线也可能距离图片近。这个时候,基于当前最新1.0.2稳定版本的约束布局已经不能知足咱们实现一层布局了,仍是须要将图片和文字总体放入一个布局容器中,而后横线依赖这个布局容器设置约束实现,嵌套好像在所不免了。然而,当约束布局1.1.0稳定版本发布时,这问题也能够获得解决。咱们先来看看在1.1.0上是怎么实现的:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
...
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="iv_course, tv_origin_price"
/>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#d8d8d8"
android:layout_marginLeft="15dp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@id/barrier"
/>
</android.support.constraint.ConstraintLayout>
复制代码
原来能够经过Barrier实现,那么Barrier是什么?请往下看。
本文主要介绍ConstraintLayout的使用,所以也不大篇幅讲述性能相关内容。
从Android studio 2.2版本开始,布局编辑器支持拖拽的方式进行约束布局。可是在2.2上布局编辑器还不是很完善,部分约束不能设置,只能经过xml输入方式实现。所以推荐用版本为2.3或者更高的Android studio。
限于篇幅,这里就不展开介绍布局编辑器了。在这里推荐两篇文章,分别是ConstraintLayout 终极秘籍(下)和 Android新特性介绍,ConstraintLayout彻底解析。看完这两篇,你们应该对布局编辑器就会有比较深刻的了解了。
在使用约束布局的过程当中,有一些须要强调的点和碰到的一些坑分享给你们。
咱们以前实现重叠布局时,会经过设置负的margin值实现。可是在约束布局中,负的margin值不会生效,只能设置0或者大于0的值,小于0也看成0处理。
通常布局咱们都是遵照先定义,后使用原则,可是约束布局实现链时,这个原则就遵照不了了。这个时候若是仍是按照常规的@id/btn_2
的方式指定依赖控件(这个控件在当前控件以后声明的),就会报Error:(23, 46) No resource found that matches the given name错误。解决方案其实很简单,只须要修改指定方式以下:@+id/btn_2
便可。
在代码中设置控件约束,能够经过ConstraintSet实现。约束变了以后,布局确定会跟着变。TransitionManager.beginDelayedTransition
提供了平滑动画变换布局的能力,可是只支持Api 19及以上的版本。
对Guideline设置相对位置属性是不生效的,所以当咱们想要一个相对于某个view的Guideline时,约束布局是不能知足咱们的要求的。 看Guideline源码:
public class Guideline extends View {
public Guideline(Context context) {
super(context);
super.setVisibility(8);
}
...
}
复制代码
发现Guideline是一个不可见的view,那么咱们能够布局时放置一个不可见的view来做为Guideline的替代品,实现一些特殊布局要求。如布局重叠:
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_bias"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.BiasActivity">
<Button
android:id="@+id/btn_a"
android:text="A"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
/>
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="1px"
app:layout_constraintBottom_toBottomOf="@id/btn_a"
android:layout_marginBottom="40dp"
/>
<Button
android:text="B"
android:background="@color/colorPrimary"
android:layout_width="wrap_content"
android:layout_height="200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/view"
/>
</android.support.constraint.ConstraintLayout>
复制代码
这种方式能够弥补margin不能设置为负值的不足,并且并无增长布局层级。
match_parent
和MATCH_CONSTRAINT
app:layout_constraintWidth_min
等约束。layout_optimizationLevel
layout_editor_absoluteX
layout_editor_absoluteY
layout_constraintBaseline_creator
layout_constraintTop_creator
layout_constraintRight_creator
layout_constraintLeft_creator
layout_constraintBottom_creator
复制代码
这几个属性是 UI 编辑器所使用的,用了辅助拖拽布局的,在实际使用过程当中,能够不用关心这些属性。
最新的约束布局beta版本,已经出到了1.1.0-beta3。在未来约束布局1.1.0版本发布后,其中会包含一下一些有意思的特性,让人看了充满期待。咱们先来一睹为快:
Barrier
Barrier是一个虚拟的辅助控件,它能够阻止一个或者多个控件越过本身,就像一个屏障同样。当某个控件要越过本身的时候,Barrier会自动移动,避免本身被覆盖。
Group
Group帮助你对一组控件进行设置。最多见的状况是控制一组控件的visibility。你只需把控件的id添加到Group,就能同时对里面的全部控件进行操做。
Circular positioning
能够相对另外一个控件,以角度和距离定义当前控件的位置,即提供了在圆上定义控件位置的能力。如图所示:
Placeholder
Placeholder顾名思义,就是用来一个占位的东西,它能够把本身的内容设置为ConstraintLayout内的其它view。所以它用来写布局的模版,也能够用来动态修改UI的内容。
百分比布局
容许设置控件占据可用空间的百分比,大大增长布局灵活度和适配性。
总而言之,约束布局的能力正在变得愈来愈强大。
曾几什么时候,对于复杂布局,不少时候不是一种布局就能够解决。这时须要考虑布局嵌套,又或者须要在代码中动态设置控件宽高比,无形中增长了开发的复杂性和布局的嵌套层级,进而影响了页面性能。随着google推出了ContraintLayout,上述的问题大部分均可以获得有效的解决。
总的来讲,ConstraintLayout优点以下:
本人经过在项目中的实践,真切体会到了ConstraintLayout应对复杂布局和自适应页面的强大能力,不但下降了布局难度,并且提高了开发效率。开发过程当中基本没怎么踩深坑,所以也很推荐你们在项目中去使用ConstraintLayout布局。
附上demo的连接github.com/yushiwo/Con…,固然更建议你们本身去写一遍,能够加深印象。