ConstraintLayout:以编程方式更改约束

Big*_*ach 76 android android-layout android-view android-constraintlayout

我需要帮助ConstraintSet.我的目标是在代码中更改视图的约束,但我无法弄清楚如何正确执行此操作.

我有4 TextView秒和1个ImageView.我需要为ImageView其中一个设置约束TextView.

check_answer4 = (TextView) findViewById(R.id.check_answer4);
check_answer1 = (TextView) findViewById(R.id.check_answer1);
check_answer2 = (TextView) findViewById(R.id.check_answer2);
check_answer3 = (TextView) findViewById(R.id.check_answer3);

correct_answer_icon = (ImageView) findViewById(R.id.correct_answer_icon);
Run Code Online (Sandbox Code Playgroud)

如果第一个答案是正确的,我需要设置的限制ImageView,以

app:layout_constraintRight_toRightOf="@+id/check_answer1"
app:layout_constraintTop_toTopOf="@+id/check_answer1"
Run Code Online (Sandbox Code Playgroud)

如果第二个答案是正确的,我需要设置的限制ImageView,以

app:layout_constraintRight_toRightOf="@+id/check_answer2"
app:layout_constraintTop_toTopOf="@+id/check_answer2"
Run Code Online (Sandbox Code Playgroud)

等等.

小智 129

  1. 要将图像视图的约束设置为:

    app:layout_constraintRight_toRightOf="@+id/check_answer1"
    app:layout_constraintTop_toTopOf="@+id/check_answer1"
    
    Run Code Online (Sandbox Code Playgroud)

    使用:

    ConstraintSet constraintSet = new ConstraintSet();
    constraintSet.clone(constraintLayout);
    constraintSet.connect(R.id.imageView,ConstraintSet.RIGHT,R.id.check_answer1,ConstraintSet.RIGHT,0);
    constraintSet.connect(R.id.imageView,ConstraintSet.TOP,R.id.check_answer1,ConstraintSet.TOP,0);
    constraintSet.applyTo(constraintLayout);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 要将图像视图的约束设置为:

    app:layout_constraintRight_toRightOf="@+id/check_answer2"
    app:layout_constraintTop_toTopOf="@+id/check_answer2"
    
    Run Code Online (Sandbox Code Playgroud)

    使用:

    ConstraintSet constraintSet = new ConstraintSet();
    constraintSet.clone(constraintLayout); 
    constraintSet.connect(R.id.imageView,ConstraintSet.RIGHT,R.id.check_answer2,ConstraintSet.RIGHT,0);      
    constraintSet.connect(R.id.imageView,ConstraintSet.TOP,R.id.check_answer2,ConstraintSet.TOP,0);
    constraintSet.applyTo(constraintLayout);
    
    Run Code Online (Sandbox Code Playgroud)

  • @Pang`.clone(constraintLayout)`这个变量是什么,我从哪里得到它? (4认同)
  • @ReejeshPK @ MiXT4PE是的,它是父布局,即“ ConstraintLayout约束布局= findViewById(R.id.parent_layout);” (4认同)
  • constraintSet.clone(constraintLayout); 在这一行中,约束布局是父布局吗? (2认同)

azi*_*ian 55

假设我们想在运行时更改约束,使button1在单击时与button2对齐:

在此输入图像描述

然后,有这个布局:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/root"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"
        app:layout_constraintTop_toTopOf="@+id/button3"
        app:layout_constraintBottom_toBottomOf="@+id/button3"
        app:layout_constraintStart_toEndOf="@+id/button3"
        android:layout_marginStart="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="0dp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:text="Button 2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.5" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:text="Button 3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.223" />
</android.support.constraint.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

我们可以做以下事情:


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button1.setOnClickListener {
            val params = button1.layoutParams as ConstraintLayout.LayoutParams
            params.leftToRight = button2.id
            params.topToTop = button2.id
            params.bottomToBottom = button2.id
            button1.requestLayout()
        }
    }

  • 先生,这是kotlin编程语言.Java等价物将是`ConstraintLayout.LayoutParams params =(ConstraintLayout.LayoutParams)button1.getLayoutParams();` (23认同)
  • @azizbekian,是的,对我来说,最终的解决方案是用“setLayoutParams()”替换“requestLayout()”调用,然后它就可以工作了。简单地改变“layoutParams”并自己请求布局似乎并不能解决问题。 (3认同)
  • @sumitsonawane,不需要,因为我们正在改变该实例,然后我们执行`button1.requestLayout()`,然后将检查我们已经改变的`LayoutParams` 实例。 (2认同)

Ast*_*liu 12

另一种方法是像这样更新视图的布局参数(不请求布局):

yourView.updateLayoutParams<ConstraintLayout.LayoutParams> {
        startToEnd = otherView.id
        topToTop = otherView.id
        bottomToBottom = otherView.id
        //add other constraints if needed
      }
Run Code Online (Sandbox Code Playgroud)

  • 哇。我不知道“View.updateLayoutParams”是一个本机扩展。这使得以编程方式更新布局参数更加干净和可读。 (3认同)

Fav*_*rem 8

我知道我的回答很晚了,但我确信它会对经常来这里的其他人有所帮助。这篇文章不是我的,但我做了一些更改,话虽如此,您应该尽力在此处查看完整的文章

约束集

在 Java 代码中使用约束集的关键是 ConstraintSet 类。此类包含一系列方法,用于执行诸如创建、配置约束以及将约束应用到 ConstraintLayout 实例等任务。此外,ConstraintLayout 实例的当前约束可以复制到 ConstraintSet 对象中,并用于将相同的约束应用于其他布局(无论有没有修改)。

ConstraintSet 实例的创建就像任何其他 Java 对象一样:

ConstraintSet set = new ConstraintSet();
Run Code Online (Sandbox Code Playgroud)

创建约束集后,可以在实例上调用方法来执行各种任务。以下代码配置一个约束集,其中 Button 视图的左侧以 70dp 的边距连接到 EditText 视图的右侧:

set.connect(button1.getId(), ConstraintSet.LEFT, 
        editText1.getId(), ConstraintSet.RIGHT, 70);
Run Code Online (Sandbox Code Playgroud)

将约束应用于布局 配置约束集后,必须将其应用于 ConstraintLayout 实例才能生效。通过调用 applyTo() 方法来应用约束集,并传递对要应用设置的布局对象的引用:

set.applyTo(myLayout);
Run Code Online (Sandbox Code Playgroud)

您可以使用 API 执行更多操作ConstraintSet,设置水平和垂直偏差、水平和垂直居中、操作链等等。

真的很好读。

再次强调,这只是一个改编。


Kof*_*fi 6

在 Kotlin 中,您可以简单地扩展ConstraintSet类并添加一些方法来利用 Kotlin 中的 dsl 并生成更具可读性的代码。像这样

class KotlinConstraintSet : ConstraintSet() {

    companion object {
        inline fun buildConstraintSet(block:KotlinConstraintSet.()->Unit) =
            KotlinConstraintSet().apply(block)
    }
    //add this if you plan on using the margin param in ConstraintSet.connect
    var margin: Int? = null
        get() {
            val result = field
            margin = null //reset it to work with other constraints
            return result
        }

    inline infix fun Unit.and(other: Int) = other // just to join two functions

    inline infix fun Int.topToBottomOf(bottom: Int) =
        margin?.let {
            connect(this, TOP, bottom, BOTTOM, it)
        } ?: connect(this, TOP, bottom, BOTTOM)

    inline fun margin(margin: Int) {
        this.margin = margin
    }

    inline infix fun Int.bottomToBottomOf(bottom: Int) =
        margin?.let {
            connect(this, BOTTOM, bottom, BOTTOM, it)
        } ?: connect(this, BOTTOM, bottom, BOTTOM)

    inline infix fun Int.topToTopOf(top: Int) =
        margin?.let {
            connect(this, TOP, top, TOP, it)
        } ?: connect(this, TOP, top, TOP)

    inline infix fun Int.startToEndOf(end: Int) =
        margin?.let {
            connect(this, START, end, END, it)
        } ?: connect(this, START, end, END)

            ...
    //TODO generate other functions depending on your needs

    infix fun Int.clear(constraint: Constraints) =
        when (constraint) {
            Constraints.TOP -> clear(this, TOP)
            Constraints.BOTTOM -> clear(this, BOTTOM)
            Constraints.END -> clear(this, END)
            Constraints.START -> clear(this, START)
        }

    //inline infix fun clearTopCon
    inline infix fun appliesTo(constraintLayout: ConstraintLayout) =
        applyTo(constraintLayout)

    inline infix fun clones(constraintLayout: ConstraintLayout) =
        clone(constraintLayout)

    inline fun constraint(view: Int, block: Int.() -> Unit) =
        view.apply(block)
}

enum class Constraints {
    TOP, BOTTOM, START, END //you could add other values to use with the clear fun like LEFT
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它

        buildConstraintSet {
            this clones yourConstraintLayout
            constraint(R.id.view1) {
                margin(value:Int) and this topToBottomOf R.id.view2
                margin(30) and this bottomToBottomOf ConstraintSet.PARENT_ID
            }
            constraint(R.id.view2) {
                this clear Constraints.BOTTOM
                margin(0) and this topToTopOf R.id.topGuide
            }
            constraint(R.id.view4) {
                this topToTopOf R.id.view2
                this bottomToBottomOf R.id.view3
                this startToEndOf R.id.view2
            }
            //or you could simply do
            R.id.view1 startToEndOf R.view2
            R.id.view1 toptToBottomOf R.view3
            R.id.view3 bottomtToBottomOf R.view2
            R.id.view3 clear Constraints.END

            // and finally call applyTo()
            this appliesTo yourConstraintLayout
        }
Run Code Online (Sandbox Code Playgroud)


Ole*_*kov 6

除了azizbekian 的回答,让我指出两件事:

  1. 如果左/右不起作用,请尝试像这样开始/结束:

params.startToEnd = button2.id

  1. 如果要删除约束,请使用 UNSET 标志,如下所示:

params.startToEnd = ConstraintLayout.LayoutParams.UNSET

  • “UNSET”非常有用,帮助解决了我遇到的问题 (2认同)

MJ *_*dio 6

您可以在ConstraintLayoutwithConstraintSetConstraintLayout.LayoutParams属性中创建约束。

我创建了一个ConstraintSetkotlin 扩展以方便使用。这既简单又健壮。

用法

 applyConstraint {
            centerHorizontallyParent(imageView)
            centerHorizontallyParent(textView)
            topToParent(imageView, px(12))
            topToBottom(textView, imageView, px(4))
        }
Run Code Online (Sandbox Code Playgroud)

代码

fun ConstraintLayout.applyConstraint(block: ConstraintSet.() -> Unit) {
    ConstraintSet().apply {
        clone(this@applyConstraint)
        block(this)
    }.applyTo(this)
}

fun ConstraintSet.centerParent(v1: View) {
    centerHorizontallyParent(v1)
    centerVerticallyParent(v1)
}

fun ConstraintSet.centerHorizontallyParent(v1: View) {
    centerHorizontally(v1.id, PARENT_ID)
}

fun ConstraintSet.centerVerticallyParent(v1: View) {
    centerVertically(v1.id, PARENT_ID)
}

fun ConstraintSet.topToTop(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, TOP, v2.id, TOP, margin)
}

fun ConstraintSet.topToParent(v1: View, @Px margin: Int = 0) {
    connect(v1.id, TOP, PARENT_ID, TOP, margin)
}

fun ConstraintSet.bottomToBottom(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, BOTTOM, v2.id, BOTTOM, margin)
}

fun ConstraintSet.bottomToParent(v1: View, @Px margin: Int = 0) {
    connect(v1.id, BOTTOM, PARENT_ID, BOTTOM, margin)
}

fun ConstraintSet.topToBottom(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, TOP, v2.id, BOTTOM, margin)
}

fun ConstraintSet.bottomToTop(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, BOTTOM, v2.id, TOP, margin)
}

fun ConstraintSet.startToStart(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, START, v2.id, START, margin)
}

fun ConstraintSet.startToParent(v1: View, @Px margin: Int = 0) {
    connect(v1.id, START, PARENT_ID, START, margin)
}

fun ConstraintSet.endToEnd(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, END, v2.id, END, margin)
}

fun ConstraintSet.endToParent(v1: View, @Px margin: Int = 0) {
    connect(v1.id, END, PARENT_ID, END, margin)
}

fun ConstraintSet.startToEnd(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, START, v2.id, END, margin)
}

fun ConstraintSet.endToStart(v1: View, v2: View, @Px margin: Int = 0) {
    connect(v1.id, END, v2.id, START, margin)
}
Run Code Online (Sandbox Code Playgroud)