ConstraintLayout:以编程方式更改约束

我需要帮助与ConstraintSet。我的目标是在代码中改变视图的约束,但我不知道如何做到这一点。

我有4个__abc0和一个ImageView。我需要将ImageView约束设置为其中一个__abc0。

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);

如果第一个答案是正确的,我需要将ImageView的约束设置为

app:layout_constraintRight_toRightOf="@+id/check_answer1"
app:layout_constraintTop_toTopOf="@+id/check_answer1"

如果第二个答案是正确的,我需要将ImageView的约束设置为

app:layout_constraintRight_toRightOf="@+id/check_answer2"
app:layout_constraintTop_toTopOf="@+id/check_answer2"

等等。

168012 次浏览
  1. 设置图像视图约束为:

     app:layout_constraintRight_toRightOf="@+id/check_answer1"
    app:layout_constraintTop_toTopOf="@+id/check_answer1"
    

    使用:

     ConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
    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);
    
  2. 设置图像视图约束为:

     app:layout_constraintRight_toRightOf="@+id/check_answer2"
    app:layout_constraintTop_toTopOf="@+id/check_answer2"
    

    使用:

     ConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
    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);
    

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

enter image description here

然后,有这样的布局:

<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>

我们可以做以下几点:


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中,你可以简单地扩展ConstraintSet类并添加一些方法来利用Kotlin中的dsl并生成更可读的代码。 这样的< / p >
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
}

像这样使用它

        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
}
我知道我的回答很晚了,但我相信它会帮助到那些经常来这里的人。 这篇文章不是我的,但我做了一些修改,也就是说,你应该努力检查完整的文章在这里

约束集

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

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

ConstraintSet set = new ConstraintSet();
一旦创建了约束集,就可以在实例上调用方法来执行广泛的任务。 下面的代码配置了一个约束集,其中Button视图的左侧连接到EditText视图的右侧,边界为70dp:

set.connect(button1.getId(), ConstraintSet.LEFT,
editText1.getId(), ConstraintSet.RIGHT, 70);

在布局中应用约束 一旦配置了约束集,它必须在ConstraintLayout实例生效之前应用到它。约束集是通过调用applyTo()方法应用的,传递一个对要应用设置的布局对象的引用:

set.applyTo(myLayout);

你可以用ConstraintSet API做更多的事情,设置水平和垂直偏差,水平和垂直居中,操作链等等。

读得真不错。

再说一次,这只是一种适应。

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

  1. 如果左/右都不行,试着这样开始/结束:

params.startToEnd = button2.id

  1. 如果你想移除一个约束,使用UNSET标志,像这样:

params.startToEnd = ConstraintLayout.LayoutParams.UNSET

@vishakha yeolekar的解决方案不适合我。

要更改约束,我们需要遵循以下步骤:

  • 克隆父布局
  • 清晰的先前的约束
  • 连接约束
  • 应用约束父布局

解决方案代码(Kotlin)

val clParent = findViewById<ConstraintLayout>(R.id.parent_layout)
val mConstraintSet = ConstraintSet()
mConstraintSet.clone(clParent)
mConstraintSet.clear(R.id.imageView, ConstraintSet.END)
mConstraintSet.connect(R.id.imageView, ConstraintSet.END, R.id.check_answer, ConstraintSet.END)
mConstraintSet.applyTo(clParent)

这里是ConstraintSet - 点击这里的更多信息和方法的链接。

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

yourView.updateLayoutParams<ConstraintLayout.LayoutParams> {
startToEnd = targetView.id
topToTop = targetView.id
bottomToBottom = targetView.id
//add other constraints if needed
}

你也可以使用TransitionManager来动画化这些变化:

public static void animateConstraintLayout(ConstraintLayout constraintLayout, ConstraintSet set, long duration) {
AutoTransition trans = new AutoTransition();
trans.setDuration(duration);
trans.setInterpolator(new AccelerateDecelerateInterpolator());


TransitionManager.beginDelayedTransition(constraintLayout, trans);
set.applyTo(constraintLayout);
}

你可以在用ConstraintSet更新布局后这样调用它:

ConstraintSet set = new ConstraintSet();
set.clone(constraintLayout);
set.connect(R.id.example, ConstraintSet.BOTTOM, R.id.anotherExample, ConstraintSet.BOTTOM);
set.connect(R.id.example, ConstraintSet.TOP, R.id.anotherExample, ConstraintSet.TOP);


animateConstraintLayout(constraintLayout, set, 500);

你可以用ConstraintSetConstraintLayout.LayoutParams属性在ConstraintLayout中创建约束。

我创建了一个ConstraintSet kotlin扩展简单使用。

使用

 applyConstraint {
centerHorizontallyParent(imageView)
centerHorizontallyParent(textView)
topToParent(imageView, px(12))
topToBottom(textView, imageView, px(4))
}

代码

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)
}