ConstraintLayout出来以后逐渐收到越来越多的Android开发者的青睐,我自己也上手使用了一年多,现在xml父布局基本都是他了。所以特开此贴聊聊ConstraintLayout。
ConstraintLayout的主要属性
这是一个用ConstraintLayout为父布局的简单页面,让我们来了解一下ConstraintLayout的主要属性。

app:layout_constraintLeft_toLeftOf=""//控件的left和父布局(parent)或者其他控件的left(@+id/控件id)形成约束
app:layout_constraintRight_toRightOf=""//控件的Right和父布局(parent)或者其他控件的Right(@+id/控件id)形成约束
app:layout_constraintTop_toTopOf=""//控件的Top和父布局(parent)或者其他控件的Top(@+id/控件id)形成约束
app:layout_constraintBottom_toBottomOf=""//控件的Bottom和父布局(parent)或者其他控件的Bottom(@+id/控件id)形成约束
app:layout_constraintLeft_toRightOf=""//控件的left和父布局(parent)或者其他控件的Right(@+id/控件id)形成约束
app:layout_constraintRight_toLeftOf=""//控件的Right和父布局(parent)或者其他控件的Left(@+id/控件id)形成约束
app:layout_constraintTop_toBottomOf=""//控件的Top和父布局(parent)或者其他控件的Bottom(@+id/控件id)形成约束
app:layout_constraintBottom_toTopOf=""//控件的Bottom和父布局(parent)或者其他控件的Top(@+id/控件id)形成约束
所谓的约束就是指的是控件的相对定位。例如,控件视图1 app:layout_constraintLeft_toLeftOf="parent" ,则是表示控件视 图1的左边相对父布局左边形成定位,此时再加上 android:layout_marginLeft="50dp"则表示控件视图1左边相对父布局左边距离50dp, 同样,以上其他属性就不难理解了。
贴上布局代码
<Button
android:id="@+id/btn_one"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="视图1"
android:layout_width="0dp"
android:layout_height="180dp"/>
<Button
android:id="@+id/btn_two"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/bth_three"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
android:text="视图2"
android:layout_width="0dp"
android:layout_height="180dp"/>
<Button
android:id="@+id/bth_three"
app:layout_constraintLeft_toRightOf="@+id/btn_two"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
android:text="视图3"
android:layout_width="0dp"
android:layout_height="180dp"/>
<Button
android:id="@+id/btn_four"
app:layout_constraintLeft_toLeftOf="@+id/btn_two"
app:layout_constraintRight_toRightOf="@+id/bth_three"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toBottomOf="parent"
android:text="视图4"
android:layout_width="0dp"
android:layout_height="0dp"/>
控件本身left和right都形成约束的时候,用0dp表示match,top和bottom也是同理。
来看下面这一组属性
app:layout_goneMarginTop=""//表示该控件top约束的目标控件的visibility=gone时,MarginTop的距离
app:layout_goneMarginBottom=""//表示该控件Bottom约束的目标控件的visibility=gone时,MarginBottom的距离
app:layout_goneMarginLeft=""//表示该控件Left约束的目标控件的visibility=gone时,MarginLeft的距离
app:layout_goneMarginRight=""//表示该控件Right约束的目标控件的visibility=gone时,MarginRight的距离

如图,当视图4所约束的视图2visibility=gone,那么视图4和视图2形成的top_toBottomof则无效,视图3和视图2的right_toleftof也失效,此时加入属性
app:layout_goneMarginTop="180dp"

属性chainStyle
app:layout_constraintHorizontal_chainStyle="packed"//如下图

app:layout_constraintHorizontal_chainStyle="spread_inside"//如下图

app:layout_constraintHorizontal_chainStyle="spread"//如下图

layout_constraintVertical_chainStyle 同理
属性Circle
主要是这三个属性,大家看代码和示意图,因为作图工具一直down不下来,所以先简单粗暴一些
app:layout_constraintCircle=""
app:layout_constraintCircleAngle=""
app:layout_constraintCircleRadius=""

<Button
android:id="@+id/btn"
android:background="#ff78D5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="50dp"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn_cir"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintCircle="@id/btn"
app:layout_constraintCircleAngle="25"
app:layout_constraintCircleRadius="100dp"
android:background="@color/colorPrimary"
android:layout_width="50dp"
android:layout_height="50dp"/>
ConstranitLayout的一些简单动画效果
android.support.constraint包里提供了一个ConstraintSet类 这个类可以设置constraintLayout的约束条件并且配合TransitionManager.beginDelayedTransition(),可以实现简单动画效果。
首先定义一个布局文件
<Button
android:id="@+id/btn_two"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_three"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorPrimary"
android:text="视图2"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_three"
app:layout_constraintLeft_toRightOf="@+id/btn_two"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorPrimaryDark"
android:text="视图3"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_four"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toBottomOf="parent"
android:text="视图4"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="0dp" />
这是作为首次进入加载的布局。然后在定义想要切换调整的布局文件,这里我定义了两个activity布局文件
activity3
<Button
android:id="@+id/btn_one"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_three"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorAccent"
android:text="视图1"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_three"
app:layout_constraintLeft_toRightOf="@+id/btn_one"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorPrimaryDark"
android:text="视图3"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_four"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
app:layout_constraintBottom_toBottomOf="parent"
android:text="视图4"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="0dp" />
activity4
<Button
android:id="@+id/btn_three"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_one"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorPrimaryDark"
android:text="视图3"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_one"
app:layout_constraintLeft_toRightOf="@+id/btn_three"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_two"
app:layout_constraintBottom_toTopOf="@+id/btn_four"
android:background="@color/colorAccent"
android:text="视图1"
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:id="@+id/btn_four"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_one"
app:layout_constraintBottom_toBottomOf="parent"
android:text="切换"
android:gravity="center"
android:layout_width="0dp"
android:layout_height="0dp" />
activity逻辑代码奉上
private val conStrainSet = ConstraintSet()
private val conStrainSet1 = ConstraintSet()
private val conStrainSet2 = ConstraintSet()
private var caseType: Int = 0
private var conStrainlayout : ConstraintLayout? = null
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
conStrainSet.clone(this,R.layout.activity_main2)
conStrainSet1.clone(this,R.layout.activity_main3)
conStrainSet2.clone(this,R.layout.activity_main4)
btn_four.setOnClickListener {
swichBtn(caseType)
}
}
private fun swichBtn(case:Int){
when(case){
0 ->{
conStrainlayout = findViewById(R.id.conStrain)
TransitionManager.beginDelayedTransition(conStrainlayout)
conStrainSet1.applyTo(conStrainlayout)
caseType = 1
}
1 ->{
conStrainlayout = findViewById(R.id.conStrain)
TransitionManager.beginDelayedTransition(conStrainlayout)
conStrainSet2.applyTo(conStrainlayout)
caseType = 2
}
2 ->{
conStrainlayout = findViewById(R.id.conStrain)
TransitionManager.beginDelayedTransition(conStrainlayout)
conStrainSet.applyTo(conStrainlayout)
caseType = 0
}
}
}
看看效果

特别要注意的是:这个activity的xml文件的父布局都需要设置id,否则ConstraintSet的clone方法就会找不到对应的资源id而报错