使用方法
//获取constraintLayout 容器里的原先的约束条件
val constraintSet = ConstraintSet().apply { this.clone(cl_container) }
//用两个控件的id添加添加约束条件
constraintSet.connect(tvTitle.id, ConstraintSet.START, cl_container.id , ConstraintSet.START)
//应用到布局的约束布局中
constraintSet.applyTo(cl_container)
1.简单归简单,但是也容易犯错。在此mark一下
比如我想根据一个map的内容动态添加一个 title: value这样的布局:
这时候就要注意:
每次循环时都要用constraintSet.clone()
方法获取原来的约束条件,即不能够把这个方法调用放到循环外,然后再拿他的引用在循环里调用...不然每一次新的循环都会把上一次的约束条件覆盖掉。
错误演示:
val constraintSet = ConstraintSet().apply { this.clone(cl_container) }
map.forEach { entry ->
//每次循环拿到的其实是布局xml文件里的约束条件,而不是每次动态添加进去后新的约束条件
constraintSet.connect(tvTitle.id, ConstraintSet.START, cl_container.id , ConstraintSet.START)
applyTo(cl_container)
2.constrainSet的获取一定要在addView的后面,不然会无法约束,造成视图消失
addView(View(this))
val constraintSet = ConstraintSet().apply { this.clone(cl_container) }
4/12更新:什么傻X东西还要按顺序调用!
关于addView和ConstraintSet().clone的调用顺序关系,实在是太奇葩了,一不留神就没留意顺序,导致约束失败,控件消失,所以我决定看一下源码...
以下是clone()的源码
public void clone(ConstraintLayout constraintLayout) {
int count = constraintLayout.getChildCount();
this.mConstraints.clear();
//拿出子view遍历
for(int i = 0; i < count; ++i) {
View view = constraintLayout.getChildAt(i);
LayoutParams param = (LayoutParams)view.getLayoutParams();
int id = view.getId();
if (id == -1) {
throw new RuntimeException("All children of ConstraintLayout must have ids to use ConstraintSet");
//把子viewId作为key,约束属性(ConstraintSet)作为value,放到一个map里
if (!this.mConstraints.containsKey(id)) {
this.mConstraints.put(id, new ConstraintSet.Constraint());
ConstraintSet.Constraint constraint = (ConstraintSet.Constraint)this.mConstraints.get(id);
constraint.fillFrom(id, param);
//设置能见度
constraint.visibility = view.getVisibility();
等等,你们发现什么没。这个clone竟然会拿到当前约束布局所有的子view,然后设置每一个的约束参数的visibility...也就是说,如果你没在clone前将子view add进去,你就相当于你新建的view都没有设置可见性...
那我们最后不是会调用apply方法,把所有动态添加的约束参数应用到约束布局中吗。难道在调用这个apply方法就不会重新设置可见度么
以下为apply方法代码
void applyToInternal(ConstraintLayout constraintLayout) {
int count = constraintLayout.getChildCount();
HashSet<Integer> used = new HashSet(this.mConstraints.keySet());
LayoutParams param;
for(int i = 0; i < count; ++i) {
View view = constraintLayout.getChildAt(i);
int id = view.getId();
if (id == -1) {
throw new RuntimeException("All children of ConstraintLayout must have ids to use ConstraintSet");
if (this.mConstraints.containsKey(id)) {
used.remove(id);
ConstraintSet.Constraint constraint = (ConstraintSet.Constraint)this.mConstraints.get(id);
param = (LayoutParams)view.getLayoutParams();
constraint.applyTo(param);
view.setLayoutParams(param);
//设置view可见性
view.setVisibility(constraint.visibility);