首页 > 编程知识 正文

android动态布局表,android线性布局的嵌套

时间:2023-05-05 23:12:05 阅读:208811 作者:4201

使用方法

//获取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.简单归简单,但是也容易犯错。在此dzdj一下

比如我想根据一个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 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);

...

}

}

}

这里可以看到view调用的方法setVisibility用的参数是根据view的id从map里拿的,而这个的前提条件是view被添加进的map里,而添加map只有在调用clone的时候。

如果你在clone后调用addview的话就会这样:

拿到 view-> 判断此id是否在map中->不在跳过了设置view的可见性方法结束.....

所以...->结果就是约束的view没了...

是的,这个就是这么沙雕,完全不知道为什么这api会这么神奇...

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。