ConstraintLayout:以编程方式更改约束
ConstraintLayout: change constraints programmatically
我需要 ConstraintSet
方面的帮助。我的目标是在代码中更改视图的约束,但我不知道如何正确地做到这一点。
我有 4 个 TextView
和一个 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);
如果第一个答案是正确的,我需要将 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"
以此类推
要将图像视图的约束设置为:
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);
要将图像视图的约束设置为:
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);
假设我们想在运行时更改约束,使按钮 1 在单击时与按钮 2 对齐:
然后,有这个布局:
<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
class 并添加一些方法来利用 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
}
然后像这样使用它
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
}
我知道我的回答已经很晚了,但我相信它会对路过这里的其他人有很大帮助。
这篇文章不是我的,但我做了一些修改,话虽这么说,你应该努力查看完整的文章 here
约束集
在 Java 代码中使用约束集的关键是约束集 class。此 class 包含一系列方法,这些方法允许执行诸如创建、配置和应用约束到 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、设置水平和垂直偏差、水平和垂直居中、操纵链等更多操作。
读得真好。
再次声明,这只是改编。
除了,我还要指出两点:
- 如果 left/right 不起作用,请像这样尝试 start/end:
params.startToEnd = button2.id
- 如果要删除约束,请像这样使用 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)
这里是 link 以获取 ConstraintSet 的更多信息和方法 - Click Here。
另一种方法是像这样更新视图的布局参数(不请求布局):
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);
我需要 ConstraintSet
方面的帮助。我的目标是在代码中更改视图的约束,但我不知道如何正确地做到这一点。
我有 4 个 TextView
和一个 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);
如果第一个答案是正确的,我需要将 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"
以此类推
要将图像视图的约束设置为:
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);
要将图像视图的约束设置为:
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);
假设我们想在运行时更改约束,使按钮 1 在单击时与按钮 2 对齐:
然后,有这个布局:
<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
class 并添加一些方法来利用 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
}
然后像这样使用它
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
}
我知道我的回答已经很晚了,但我相信它会对路过这里的其他人有很大帮助。 这篇文章不是我的,但我做了一些修改,话虽这么说,你应该努力查看完整的文章 here
约束集
在 Java 代码中使用约束集的关键是约束集 class。此 class 包含一系列方法,这些方法允许执行诸如创建、配置和应用约束到 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、设置水平和垂直偏差、水平和垂直居中、操纵链等更多操作。
读得真好。
再次声明,这只是改编。
除了
- 如果 left/right 不起作用,请像这样尝试 start/end:
params.startToEnd = button2.id
- 如果要删除约束,请像这样使用 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)
这里是 link 以获取 ConstraintSet 的更多信息和方法 - Click Here。
另一种方法是像这样更新视图的布局参数(不请求布局):
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);