常用属性
宽度或者高度设置为0dp的时候表示充满约束:match constraint
权重属性(水平权重,垂直权重)
使用权重时,宽度或者高度要充满约束。
layout_constraintHorizontal_weightlayout_constraintVertical_weight
文字基准线对齐
单位前面加上数字需要以文字的下面为基准:

app:layout_constraintBaseline_toBaselineOf="@id/money_tv"
这样让¥的符号和前面的数字的baseline在一条线。
约束链风格
如果几个View想要一起做一些操作

约束链
layout_constraintVertical_chainStyle默认风格是spread格式,就是第一个风格。如果想要使用约束链比如第一种格式,需要几个
View相互联系,相互约束才能实现。比如:
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
android:textSize="30dp"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/content"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintBottom_toBottomOf="parent"
android:text="这是内容"/>
这样两个TextView在一起实现了屏幕居中。
宽高比例
约束布局中可以使用宽高比例来设置View的大小
app:layout_constraintDimensionRatio="1:1"
这样宽和高的比例就是1:1。
如果在比例的前面加上W或者H表示宽和高是计算得出:
app:layout_constraintDimensionRatio="W,1:1"
文字和其他View宽度一致
比如上面是一个ImageView,下面是TextView,TextView的宽度不定,而TextView最大宽度需要和ImageView宽度保持一致:
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="萨拉的风景案例的风景阿萨拉的风景"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="@id/iv"
app:layout_constraintStart_toStartOf="@id/iv"
app:layout_constraintTop_toBottomOf="@id/iv" />
上面布局中的TextView宽度受到iv的约束,最大宽度不会超过iv。
如果两边同时约束,但是又想偏向某个方向可是使用
layout_constraintHorizontal_bias横向偏向
layout_constraintVertical_bias竖向偏向
当一个view根据另外一个view布局,另外一个view隐藏的时候,view需要间距
- layout_goneMarginBottom
- layout_goneMarginEnd
- layout_goneMarginTop
- layout_goneMarginStart
Guideline使用
guideline相当于在布局中加了一条隐藏的线,可以以这条线为基准进行布局:
可以指定guideline为竖线还是横线。
android:orientation="vertical"
android:orientation="horizontal"
guideline的位置可以用begin或者end还有百分比percent来指定。
app:layout_constraintGuide_begin="60dp"
app:layout_constraintGuide_percent="0.2"
比如下图中我使用了两条guideline,一条是60dp的竖线和一条百分比是20%的横线:

使用方法如下:
<androidx.constraintlayout.widget.Guideline
android:id="@+id/v_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="60dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/h_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.2" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/user_et"
android:layout_width="200dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/h_guideline"
app:layout_constraintStart_toStartOf="@id/v_guideline" />
根据圆的位置设置布局
设置圆心
app:layout_constraintCircle
设置角度
app:layout_constraintCircleAngle
设置半径:
app:layout_constraintCircleRadius
如果半径设置为
0则放在圆心的位置。所以如果半径小的话,有可能会和圆心的view重叠。
下图表示以circle_iv为圆心,在半径200dp角度是30度的地方放了一个out_iv:

使用方法如下:
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/circle_iv"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/out_iv"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintCircle="@id/circle_iv"
app:layout_constraintCircleAngle="30"
app:layout_constraintCircleRadius="200dp" />
Placeholder使用
placeholder可以替换成其他的view:
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/place_holder"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
当点击下面的imageview的时候可以将placeholder替换成imageview:
place_holder.setContentId(R.id.iv)
进入setContentId方法:
public void setContentId(int id) {
this.mContentId = id;
}
这个方法会将mContentId换成要替换的id,然后执行updatePreLayout方法:
public void updatePreLayout(ConstraintLayout container) {
this.mContent = container.findViewById(this.mContentId);
}
根据mContentId找到view并赋值给mContent,随后进行布局:
public void updatePostMeasure(ConstraintLayout container) {
if (this.mContent != null) {
LayoutParams layoutParams = (LayoutParams)this.getLayoutParams();
LayoutParams layoutParamsContent = (LayoutParams)this.mContent.getLayoutParams();
layoutParamsContent.widget.setVisibility(0);
//将要替换view的宽高赋值给placeholder
layoutParams.widget.setWidth(layoutParamsContent.widget.getWidth());
layoutParams.widget.setHeight(layoutParamsContent.widget.getHeight());
//再将要替换的view隐藏
layoutParamsContent.widget.setVisibility(8);
}
}
最后执行onDraw方法。
如果想要对一些View做整体操作比如隐藏或者显示可以使用Group
<androidx.constraintlayout.widget.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="tv"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
group.visibility = View.GONE
在constraint_referenced_ids里面的View就会全部隐藏。
Barrier使用
barrier表示屏障的意思,比如有多个view,总是以最长的view为最大宽度,然后barrier后面再添加其他view。

在
tv1和tv2的后面并且以这两个最宽的为屏障在后面添加iv控件。
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="tv1, tv2" />
constraint_referenced_ids表示作用宽度的控件。
barrierDirection表示添加到那些控件的位置。
Group和Barrier都是继承ConstraintHelper类
我们可以根据需求来自定义ConstraintHelper。
ConstraintHepler中设置的View个数默认是32个:
protected int[] mIds = new int[32];
在ConstraintLayout的onMeasure中执行
private void updatePostMeasures() {
helperCount = this.mConstraintHelpers.size();
if (helperCount > 0) {
for(int i = 0; i < helperCount; ++i) {
ConstraintHelper helper = (ConstraintHelper)this.mConstraintHelpers.get(i);
helper.updatePostMeasure(this);
}
}
}
onLayout中执行:
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
helperCount = this.mConstraintHelpers.size();
if (helperCount > 0) {
for(int i = 0; i < helperCount; ++i) {
ConstraintHelper helper = (ConstraintHelper)this.mConstraintHelpers.get(i);
helper.updatePostLayout(this);
}
}
}
可以发现会执行ConstraintHelper的updatePostMeasure和updatePostLayout方法,可以在这两个方法中对View做一些操作。
使用ConstraintSet自定义布局或者替换Layout
val constraintLayout = view as ConstraintLayout
val constraintSet = ConstraintSet().apply {
clone(this@TestActivity, "要替换的布局")
}
//添加过渡动画
TransitionManager.beginDelayedTransition(constraintLayout)
constraintSet.applyTo(constraintLayout)