更新
我想提一下,Remq的回答有效地解决了我在下面提到的自引用问题,其中一个视图的宽度取决于使用相同视图作为引用ID的屏障的位置。关键似乎是对两个视图都指定 app:layout_constraintWidth_min="wrap"
。我不清楚为什么这样做有效,或者它是否会继续有效,但我想记录一下。
更新#2
我再次查看了Remq答案有效的原因。我的经验是,在未为视图指定 app:layout_constraintWidth_min="wrap"
时,两个视图的宽度都会折叠为零。一旦视图测量出零宽度, app:layout_constraintWidth_min="wrap"
会再次使它们增长,以便内容被包裹。这只是我推测的,我没有证据证明正在发生这种情况,但这是有道理的。
我在Stack Overflow上多次看到类似这个问题的问题。在我看来,这些问题从未有过令人满意的答案(包括我回答的问题)。困难在于存在依赖性问题,因为一个视图依赖于另一个视图的宽度,而另一个视图依赖于第一个视图的宽度。我们陷入了自我引用的困境。(强制以编程方式设置宽度始终是一种选择,但似乎不可取。)
另一种更好的方法是使用自定义 ConstraintHelper ,该方法将检查所引用视图的大小并调整所有视图的宽度以适应最大宽度。
自定义 ConstraintHelper 放置在布局的XML中,并引用如下示例布局中的受影响视图:
activity_main
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:text="Button1"
app:layout_constraintBottom_toTopOf="@+id/button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Button2 may be larger"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button1" />
<com.example.constraintlayoutlayer.GreatestWidthHelper
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="button1,button2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
自定义的ConstraintHelper如下所示:
GreatestWidthHelper
class GreatestWidthHelper @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
override fun updatePostMeasure(container: ConstraintLayout) {
var maxWidth = 0
// Find the greatest width of the referenced widgets.
for (i in 0 until this.mCount) {
val id = this.mIds[i]
val child = container.getViewById(id)
val widget = container.getViewWidget(child)
if (widget.width > maxWidth) {
maxWidth = widget.width
}
}
// Set the width of all referenced view to the width of the view with the greatest width.
for (i in 0 until this.mCount) {
val id = this.mIds[i]
val child = container.getViewById(id)
val widget = container.getViewWidget(child)
if (widget.width != maxWidth) {
widget.width = maxWidth
// Fix the gravity.
if (child is TextView && child.gravity != Gravity.NO_GRAVITY) {
// Just toggle the gravity to make it right.
child.gravity = child.gravity.let { gravity ->
child.gravity = Gravity.NO_GRAVITY
gravity
}
}
}
}
}
}
布局如下所示。
ConstraintLayout
中让某些东西工作,最好避免使用它。 - Farid<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:text="Button1"
app:layout_constraintBottom_toTopOf="@+id/button2"
app:layout_constraintEnd_toEndOf="@id/barrierEnd"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintWidth_min="wrap" />
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Button2 may be larger"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/barrierEnd"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button1"
app:layout_constraintWidth_min="wrap" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrierEnd"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="end"
app:constraint_referenced_ids="button1,button2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
目前还无法将它们水平居中,如果有人找到了解决方法,我会更新这个示例。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello world"
app:layout_constraintBottom_toTopOf="@+id/text2"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello world"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text1" />
</androidx.constraintlayout.widget.ConstraintLayout>