ConstraintLayout约束布局使用全解

目的

为何:布局扁平化,减少布局层级,即提高性能;

约束布局 默认需要一个垂直方向和水平方向的约束;

约束布局中的宽高的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)

猜你喜欢

转载自blog.csdn.net/LucasXu01/article/details/127603015