在ConstraintLayout中程序化地移除/添加约束条件

79

我希望能够根据某些条件程序化地删除和添加约束。以下是截图:

按钮“创建广告”有一个顶部约束

我想在代码中实现类似以下的效果:

这里是已删除了顶部约束的按钮

所以我想通过编程方式实现相同的效果。

以下是我尝试的代码:

    if (advertisements.size() > 0) { //my own condition
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) btnCreateAd.getLayoutParams();
        layoutParams.topToBottom = R.id.imvEmpty; //the imageview that is in center of the view
        btnCreateAd.setLayoutParams(layoutParams);
        recyclerView.setVisibility(View.VISIBLE);
        txvMyAdEmptyText.setVisibility(View.GONE);
        imvEmpty.setVisibility(View.GONE);
        adapter.setList(advertisements);
        adapter.notifyDataSetChanged();
    } else {
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) btnCreateAd.getLayoutParams();
        layoutParams.topToBottom = -1; //here i am trying to remove top constraint but it doesn't work
        btnCreateAd.setLayoutParams(layoutParams);

        recyclerView.setVisibility(View.GONE);
        txvMyAdEmptyText.setVisibility(View.VISIBLE);
        imvEmpty.setVisibility(View.VISIBLE);
        adapter.setList(new ArrayList<Advertisement>());
    }
    mConstraintView.invalidate(); //this is my constraint view

编辑

我也尝试过使用ConstraintSet,但结果却不同,我的RecyclerView(设置为父视图的边界)不知何故消失了。

 ConstraintSet set = new ConstraintSet();
    set.clone(parentView);

    if (advertisements.size() > 0) {

        recyclerView.setVisibility(View.VISIBLE);
        txvMyAdEmptyText.setVisibility(View.GONE);
        imvEmpty.setVisibility(View.GONE);
        adapter.setList(advertisements);
        adapter.notifyDataSetChanged();

    } else {

        set.connect(btnCreateAd.getId(), ConstraintSet.TOP, imvEmpty.getId(), ConstraintSet.BOTTOM, 0);

        recyclerView.setVisibility(View.GONE);
        txvMyAdEmptyText.setVisibility(View.VISIBLE);
        imvEmpty.setVisibility(View.VISIBLE);
        adapter.setList(new ArrayList<Advertisement>());
    }
    set.connect(btnCreateAd.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0);
    set.connect(btnCreateAd.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 0);
    set.connect(btnCreateAd.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0);

    set.applyTo(parentView);

看看这个是否有帮助:https://dev59.com/Zm435IYBdhLWcg3w-lP2 - Valdio
@ValdioVeliu 抱歉,但那是针对RelativeLayout参数的,我需要从constraintLayoutParams获取。 - Damir Mailybayev
@Chisko 我也尝试过使用ConstraintSet,但对于这种情况它并不起作用,而且还会破坏其他视图的约束条件。顺便说一下,所有视图都已经在布局中创建好了(我的意思是我没有动态创建视图)。 - Damir Mailybayev
4个回答

182

我还没有仔细研究你的代码,但以下内容演示了使用ConstraintSet打破和创建约束的方法。

ConstraintSet set = new ConstraintSet();
ConstraintLayout layout;

layout = (ConstraintLayout) findViewById(R.id.layout);
set.clone(layout);
// The following breaks the connection.
set.clear(R.id.bottomText, ConstraintSet.TOP);
// Comment out line above and uncomment line below to make the connection.
// set.connect(R.id.bottomText, ConstraintSet.TOP, R.id.imageView, ConstraintSet.BOTTOM, 0);
set.applyTo(layout);

终于找到了一种编程方式来移除约束,谢谢。 - Lalit Fauzdar
@DominikusK,谢谢你提醒我!如果你对这些转换动画感兴趣,这篇文章会很有帮助。 - bmjohns
有人注意到在更改约束条件时,使用Api 21或22和ConstraintLayout 1.1.1存在问题吗?似乎有点不可靠,但在api 28上完美运行。 - Bakhshi
是的@Bakhshi,我也注意到了这个问题。你解决了吗?如果是的话,怎么解决的?我正在使用1.1.3版本。 - Shubham Gupta
set.clone(layout); 这行代码非常重要,因为如果没有这行代码,我应用后的布局会消失。 - Reejesh PK

19
如果您正在使用Kotlin与viewBinding/dataBinding,现在有一种更简单的方法来完成它。
有一个名为updateLayoutParams的扩展函数,它来自于import androidx.core.view.updateLayoutParams,可以像下面这样使用。

    binding.yourView.updateLayoutParams<ConstraintLayout.LayoutParams> {
                        this.startToEnd = ConstraintLayout.LayoutParams.UNSET
                      this.startToStart = ConstraintLayout.LayoutParams.PARENT_ID
                    }


3
这对我来说是目前为止最好的答案!!ConstraintLayout.LayoutParams.UNSET。它是最复杂和最新的更新,用于以编程方式更新布局参数。 - Marfin. F
1
这真的是最好的答案,像魔法一样有效。 - Mosa

19

另一种方法是使用ConstraintLayout.LayoutParams.UNSET。这种方法不使用ConstraintSet.clear

假设我们想要删除constraintLayout本身的底部约束,但可以是任何视图:

val containerParams = cl_container.layoutParams as ConstraintLayout.LayoutParams
containerParams.bottomToBottom = ConstraintLayout.LayoutParams.UNSET
cl_container.layoutParams = containerParams

你可以提供这段代码的Java版本吗? - Nalin Angrish
1
Kotlin和Java是可以互换的。在IDE或在线上寻找更改选项。 - j2emanue

4
这是Java版本的答案,来自j2emanue,使用ConstraintLayout.LayoutParams,它可以在不指定布局约束目标元素的ID的情况下工作:
final ConstraintLayout constraintLayout = findViewById(R.id.constraintLayout);
final ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) constraintLayout.getLayoutParams();
layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.UNSET;
constraintLayout.setLayoutParams(layoutParams);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接