文章目录
目的
为何:布局扁平化,减少布局层级,即提高性能;
约束布局 默认需要一个垂直方向和水平方向的约束;
约束布局中的宽高的0dp含义:充满约束
宽高:match_constraint:充满父容器约束
居中
居中于⽗容器
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
居中于控件中⼼
⽔平⽅向居中
app:layout_constraintStart_toStartOf="@id/view"
app:layout_constraintEnd_toEndOf="@id/view"
垂直⽅向居中
app:layout_constraintTop_toTopOf="@id/view"
app:layout_constraintBottom_toBottomOf="@id/view"
居中于控件的边
控件垂直居中于 view 的「下边」
app:layout_constraintTop_toBottomOf="@id/view"
app:layout_constraintBottom_toBottomOf="@id/view"
填充
⽔平⽅向填充⽗容器(通过 match_constraint
)
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="0dp"
备注:在早期版本中 match_parent 没有效果。
权重
为⽔平⽅向的控件设置权重,⼤⼩为 2:1:1 。
<!-- (view-1) -->
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="2"
<!-- (view-2) -->
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1"
<!-- (view-3) -->
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1"
⽂字基准线对⻬
app:layout_constraintBaseline_toBaselineOf
圆形定位
通过「圆⼼」「⻆度」「半径」设置圆形定位
app:layout_constraintCircle="@id/view"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="180dp"
特殊属性
约束限制
限制控件⼤⼩不会超过约束范围。
app:layout_constrainedWidth="true"
app:layout_constrainedHeight="true
偏向
控制控件在垂直⽅向的 30%的位置
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.3"
除了配合百分⽐定位,还有⽤于配合有时在「约束限制」的条件下不需要居中效果
的情况
垂直⽅向居顶部
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constrainedHeight="true"
app:layout_constraintVertical_bias="0.0"
约束链
在约束链上的第⼀个控件上加上 chainStyle
,⽤来改变⼀组控件的布局⽅式
-
packed(打包)
-
spread (扩散)
-
spread_inside(内部扩散)
垂直⽅向 packed
app:layout_constraintVertical_chainStyle="packed"
宽⾼⽐
-
⾄少需要⼀个⽅向的值为
match_constraint
-
默认的都是「宽⾼⽐」,然后根据另外⼀条边和⽐例算出match_constraint 的值
宽高比,宽高都是0dp,即充满父约束指定高是计算出来的:
android:layout_height = "0dp"
android:layout_width = "0dp"
app:layout_constraintDimensionRatio = "H,2:1"
百分⽐布局
-需要对应⽅向上的值为 match_constraint
-百分⽐是 parent 的百分⽐,⽽不是约束区域的百分⽐
宽度是⽗容器的 30%
android:layout_width="0dp"
app:layout_constraintWidth_percent="0.3"
辅助控件GuideLine
-
设置辅助线的⽅向 android:orientation=“vertical”
-
设置辅助线的位置,根据⽅向不同:
距离左侧或上侧的距离 layout_constraintGuide_begin
距离右侧或下侧的距离 layout_constraintGuide_end
百分⽐ layout_constraintGuide_percent
Group
通过 constraint_referenced_ids 使⽤引⽤的⽅式来避免布局嵌套。
可以为⼀组控件统⼀设置 setVisibility
只有设置可⻅度的功能,不要指望这个来通知设置点击事件…
Layer
和 Group 类似,同样通过引⽤的⽅式来避免布局嵌套,可以为⼀组控件统⼀设置旋
转/缩放/ 位移。
Barrier
通过设置⼀组控件的某个⽅向的屏障,来 避免布局嵌套 。
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android: layout_width="wrap_content"
android: layout_height="wrap_content"
app: barrierDirection="end"
app: constraint_referenced_ids="viewl, view2"/>
ConstraintHelper
example:用声明写动画
import android.view.ViewAnimationUtils
import androidx.constraintlayout.widget.ConstraintHelper
import androidx.constraintlayout.widget.ConstraintLayout
import kotlin.math.hypot
class CircularRevealHelper(context: Context, attrs: AttributeSet) : ConstraintHelper(context, attrs) {
override fun updatePostLayout (container: ConstraintLayout) {
super.updatePostLayout (container)
referencedIds.forEach {
val view = container.getViewById(it)
val radius = hypot (view.width.toDouble(), view.height.toDouble()).toInt ()
ViewAnimationUtils.createCircularReveal(view, centerX: 0, centerY: 0, startRadius: Of, radius.toFloat())
.setDuration(2000L)
.start()
}
}
}
<androidx.constraintlayout.widget.ConstraintLayout
...
>
...
<com.hencoder.CircularRevealHelper
android: layout _width="wrap_content"
android: layout_height="wrap_content"
app:constraint_referenced_ ids="image1, image2, image3, image4"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Placeholder
通过 setContentId 来将指定控件放到占位符的位置。
findViewById<Pfaceholder>(R.id.placeholder).setContentId(view.id)
Flow
通过引⽤的⽅式来避免布局嵌套。
wrapMode
-
chain
-
aligned
-
none(默认)
注意这个控件是可以被测量的,所以对应⽅向上的值可能需要被确定(即不能只约束同⼀⽅ 向的单个约束)
<androidx. constraintlayout.helper.widget.Flow
android: id="@+id/flow"
android: layout width="Odp"
android: layout_height="wrap_content"
android: layout _marginStart="16dp"
android: layout_marginTop="16dp"I
android: background="@color/colorAccent"
android:orientation="horizontal"
app: flow wrapMode="chain"
app: flow verticalGap="16dp" //竖直间距
app: flow_horizontalGap="16dp"//水平间距
app: constraint_referenced_ids="viewl, view2, view3, view4"
app: layout_constraintStart_toStartOf="parent"
app: layout_constraintTop_toTopOf="parent"/>
自定义一个简单linearLayout
class Linear (context: Context, attrs: AttributeSet) : VirtualLayout (context, attrs) {
private val constraintSet: ConstraintSet by lazy {
ConstraintSet().apply { this: ConstraintSet
isForceld = false
}
override fun updatePreLayout (container: ConstraintLayout) {
super.updatePreLayout (container)
constraintSet.clone(container)
val viewIds : IntArray! = referencedIds;
for (i: Int in 1 until mCount) {
val current: Int = viewIds[i]
val before : Int = viewIds[i - 1]
constraintSet. connect (current, ConstraintSet.START, before, ConstraintSet.START)
constraintSet.connect (current, ConstraintSet.TOP, before, ConstraintSet.BOTTOM)
constraintSet.applyTo(container)
}
}
}
ConstraintSet
使⽤ ConstraintSet 对象来动态修改布局。通过 ConstraintSet#clone 来从 xml 布局中获取约束集。
val constraintLayout = view as ConstraintLayout
val constraintSet = ConstraintSet ().apply { this: ConstraintSet
clone (constraintLayout)
connect (
R.id.twitter,
ConstraintSet.BOTTOM,
ConstraintSet.PARENT_ID,
ConstraintSet.BOTTOM
)
}
constraintSet.applyTo(constraintLayout)
防⽌布局中有⽆ id 控件时报错,需要设置 isForceId = false
布局扁平化更加容易做过渡动画
在布局修改(constraintSet)之前加上 TransitionManager 来⾃动完成过渡动画。
constraintSet如果采用代码的方式编写,较为复杂,可以写两个xml布局,一个动画之前的,一个动画之后的,再用clone,将constraintSet吸出来,加以动画即可:
TransitionManager.beginDelayedTransition(constraintLayout)