今天项目有需要动态设置ConstrainLayout这个布局的需求,在网上搜了一下,记录一下大致的流程和可能出现问题的点

一、获取要设置目标控件的父布局。

val constraintLayoutRoot = getView<ConstraintLayout>(R.id.constraint_dynamics_root)

二、实例化一个ConstraintSet(),此类是用来动态设置约束的合集。

val constraintSet = ConstraintSet()

三、将布局中的约束克隆出来,赋值给第二步实例化的constraintSet对象,常用的有三种克隆方法,这里我们使用第一种克隆方法。

1、constraintSet.clone(constraintLayout: ConstraintLayout) //克隆第一步获取到的constraintLayout

2、constraintSet.clone(set: ConstraintSet) //克隆其他的constraintSet()

3、constraintSet.clone(context: Context, constraintLayoutId: Int) //直接克隆父布局id。

四、动态修改约束。常用方法有以下两种,由参数上可见,第二个方法多了一个添加间距的参数,所以使用时,可以根据情况调用不同方法。

1、public void connect(int startID, int startSide, int endID, int endSide) {}

2、public void connect(int startID, int startSide, int endID, int endSide, int margin) {}

startID:要约束的目标控件id。
startSide:要约束的目标控件的边界。
endID:约束条件控件的id。
endSide:endID的边界。
int margin:间距。

举个例子

比如将view_divider的左边约束于tv_company_name的左边,就可以写成

constraintSet.connect(R.id.view_divider,ConstraintSet.START, R.id.tv_company_nam,ConstraintSet.START)

如果要相对父布局设置约束,可以写成

constraintSet.connect(R.id.view_divider,ConstraintSet.START, ConstraintSet.PARENT_ID,ConstraintSet.START)

要设置间距,添加一个margin参数即可

constraintSet.connect(R.id.view_divider,ConstraintSet.START, ConstraintSet.PARENT_ID,ConstraintSet.START,20)

其他方向的约束同理。 constraintSet()还可以方便的设置控件的宽高:

// 设置宽度 constraintSet.constrainWidth(viewId, ConstraintSet.WRAP_CONTENT) // 或者 ConstraintSet.MATCH_CONSTRAINT

// 设置高度 constraintSet.constrainHeight(viewId, 100) // 设置具体的高度值,也可以是 ConstraintSet.WRAP_CONTENT 或 ConstraintSet.MATCH_CONSTRAINT

五、最后一定不要忘记applyTo应用约束。(调用applyTo()方法即可应用约束。)

constraintSet.applyTo(constraintLayoutRoot)

注意

  1. 克隆出来的constraintSet()只是一个克隆体,对其进行的各种约束操作,最后都要applyTo()才能生效,如果想要清空之前的约束,可以使用
    constraintSet.clear(viewId)
  2. 当使用ConstraintSet的时候,约束布局里的所有view都必须要有id,不然会报错。

我在使用的时候用到了clear方法

// 清除所有约束 constraintSet.clear(viewId) // 或者清除特定方向的约束 constraintSet.clear(viewId, ConstraintSet.START)
constraintSet.clear(viewId, ConstraintSet.END)
constraintSet.clear(viewId, ConstraintSet.TOP)
constraintSet.clear(viewId, ConstraintSet.BOTTOM)

因为在重新设置某个view的约束时,并不一定四个都要设置,但是原来xml文件里写入的约束例如

app:layout_constraintTop_toTopOf="@id/tv_waiter"


但是在代码里不需要这个toptotop了,因此可以使用clear方法清除这个toptotop constraintSet.clear(R.id.tv_people,ConstraintSet.END)

其实应该也可以直接使用constraintSet.clear(R.id.tv_people),在重新设置约束是没有效果的,这一点还没找到原因,因此就按刚刚说的来