常用属性
宽度或者高度设置为0dp
的时候表示充满约束:match constraint
权重属性(水平权重,垂直权重)
使用权重时,宽度或者高度要充满约束。
layout_constraintHorizontal_weight
layout_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];
在ConstraintLayou
t的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)