ConstraintLayout 简介
约束布局ConstraintLayout 是一个ViewGroup,可以在Api 9以上的Android系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。从 Android Studio 2.3 起,官方的模板默认使用 ConstraintLayout。
如:
<?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=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
使用其,需要在app/build.gradle文件中添加ConstraintLayout的依赖:
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
}
ConstraintLayout的优势:
避免布局嵌套过多的问题,并且使用起来比RelativeLayout更灵活,性能更出色。ConstraintLayout还可以按照比例约束控件位置和尺寸,能够更好地适配屏幕大小不同的机型。
Android Demo
Relative positioning 相对定位
我们要显示这个效果图的布局:
布局代码:
<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=".MainActivity">
<TextView
android:id="@+id/textView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView01"
android:visibility="visible" />
<TextView
android:id="@+id/textView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView02"
app:layout_constraintLeft_toRightOf="@id/textView01" />
<TextView
android:id="@+id/textView03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView03"
app:layout_constraintTop_toBottomOf="@id/textView01" />
</android.support.constraint.ConstraintLayout>
事实上,我们一看代码主会明白代码的具体含义,都不需要做说明了。
下面来看看相对定位的常用属性:
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
这其中,一个剧中的组合:
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
Circular positioning 角度定位
具体的原理如图:
代码为:
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />
我们布局一个如下图的UI界面:
布局代码:
<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=".MainActivity">
<TextView
android:id="@+id/textView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView01" />
<TextView
android:id="@+id/textView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView02"
app:layout_constraintCircle="@+id/textView01"
app:layout_constraintCircleRadius="50dp"
app:layout_constraintCircleAngle="135" />
<TextView
android:id="@+id/textView03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="textView03"
app:layout_constraintCircle="@+id/textView02"
app:layout_constraintCircleRadius="50dp"
app:layout_constraintCircleAngle="135" />
</android.support.constraint.ConstraintLayout>
Margins 边距
边距常用属性如下:
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
我们要显示如下UI:
布局文件为:
<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=".MainActivity">
<TextView
android:id="@+id/textView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="textView01"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/textView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="textView02"
android:layout_marginLeft="20dp"
android:layout_marginTop="40dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Centering positioning and bias 居中和偏移
简单的控件居中:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
控件偏移比例主要是下面二个属性:
layout_constraintHorizontal_bias
layout_constraintVertical_bias
官网给的水平 3:7的显示样例:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
Widgets dimension constraints 尺寸约束
The dimension of the widgets can be specified by setting the android:layout_width and android:layout_height attributes in 3 different ways:
Using a specific dimension (either a literal value such as 123dp or a Dimension reference)
Using WRAP_CONTENT, which will ask the widget to compute its own size
Using 0dp, which is the equivalent of “MATCH_CONSTRAINT”
也就是说指定控件大小,主要是上面说的三种方法。
第一种和第二种就不介绍,主要介绍第三种:
宽或高至少有一个尺寸被设置为0dp时,可以通过属性layout_constraintDimensionRatio设置宽高比。
宽设置为0dp,宽高比设置为1:1,这个时候TextView1是一个正方形:
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
除此之外,在设置宽高比的值的时候,还可以在前面加W或H,分别指定宽度或高度限制。 例如:
app:layout_constraintDimensionRatio=“H,2:3” 指的是 高:宽=2:3
app:layout_constraintDimensionRatio=“W,2:3” 指的是 宽:高=2:3
我们要显示一个1:1的textView01和高度为2:3的textView02 UI如图:
显示代码:
<?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=".MainActivity">
<TextView
android:id="@+id/textView01"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="textView01"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/textView02"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="textView02"
app:layout_constraintDimensionRatio="H,2:3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView01" />
</android.support.constraint.ConstraintLayout>
Chains 链
Creating a chain:
Chain heads:
Chain Style:
When setting the attribute layout_constraintHorizontal_chainStyle or layout_constraintVertical_chainStyle on the first element of a chain, the behavior of the chain will change according to the specified style (default is CHAIN_SPREAD).
Weighted chains 显示大小比例:
layout_constraintHorizontal_weight
layout_constraintVertical_weight
我们要显示如图UI,TextView01:TextView02:TextView03=2:4:8,
显示代码:
<?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=".MainActivity">
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2"
app:layout_constraintHorizontal_weight="2" />
<TextView
android:id="@+id/TextView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView2"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="4" />
<TextView
android:id="@+id/TextView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView3"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="8" />
</android.support.constraint.ConstraintLayout>
Optimizer
当我们使用 MATCH_CONSTRAINT 时,ConstraintLayout 将对控件进行 2 次测量,ConstraintLayout在1.1中可以通过设置 layout_optimizationLevel 进行优化,可设置的值有:
none:无优化
standard:仅优化直接约束和屏障约束(默认)
direct:优化直接约束
barrier:优化屏障约束
chain:优化链约束
dimensions:优化尺寸测量
Barrier
Barrier可以在多个控件的一侧建立一个屏障:
如下UI效果图:
<?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=".MainActivity">
<TextView
android:id="@+id/TextView1"
android:text="TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView2 and ......"
app:layout_constraintTop_toBottomOf="@+id/TextView1" />
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="TextView1,TextView2" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView3"
app:layout_constraintLeft_toRightOf="@+id/barrier" />
</android.support.constraint.ConstraintLayout>
app:barrierDirection为屏障所在的位置,可设置的值有:bottom、end、left、right、start、top
app:constraint_referenced_ids为屏障引用的控件,可设置多个(用“,”隔开)
Group
Group可以把多个控件归为一组,方便隐藏或显示一组控件,举个例子:
<?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=".MainActivity">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView01 "/>
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView02 "
app:layout_constraintLeft_toRightOf="@+id/TextView1" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView03 "
app:layout_constraintLeft_toRightOf="@id/TextView2" />
</android.support.constraint.ConstraintLayout>
现在有3个并排的TextView,用Group把TextView1和TextView3归为一组,再设置这组控件的可见性,如下所示:
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:constraint_referenced_ids="TextView1,TextView3" />
效果如下:
Placeholder
Placeholder指的是占位符。在Placeholder中可使用setContent()设置另一个控件的id,使这个控件移动到占位符的位置。举个例子:
<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=".MainActivity">
<android.support.constraint.Placeholder
android:id="@+id/placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:content="@+id/textview"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#cccccc"
android:padding="16dp"
android:text="TextView"
android:textColor="#000000"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
新建一个Placeholder约束在屏幕的左上角,新建一个TextView约束在屏幕的右上角,在Placeholder中设置 app:content="@+id/textview",这时TextView会跑到屏幕的左上角。效果如下:
Guideline
Guildline像辅助线一样,在预览的时候帮助你完成布局(不会显示在界面上)。
Guildline的主要属性:
android:orientation 垂直vertical,水平horizontal
layout_constraintGuide_begin 开始位置
layout_constraintGuide_end 结束位置
layout_constraintGuide_percent 距离顶部的百分比(orientation = horizontal时则为距离左边)
参考资料
1.约束布局ConstraintLayout看这一篇就够了
https://www.jianshu.com/p/17ec9bd6ca8a
2.ConstraintLayout 官网
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout