约束布局 - 宽度最大的两个视图

7

我想创建一个像下面这样的布局(使用约束布局):

enter image description here

在不同语言环境下,Button1 可能比 Button2 更大。如何实现这个效果?

我只能通过在包含这两个按钮的约束内部使用 LinearLayout 来实现此目标,但我希望只使用一个布局。

谢谢。


请发布您正在使用的LinearLayout工作的XML代码!我将帮助您将其转换为ConstraintLayout。 - Rujul Gandhi
3个回答

16

更新

我想提一下,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
                    }
                }
            }
        }
    }
}

布局如下所示。

enter image description here


1
谢谢!然而,在ConstraintLayout轻松支持之前,我将使用LinearLayout解决方案。 - Mateu
@Mateu LinearLayout的解决方案是可以接受的(在我看来),但有些人可能会反对离开平面布局。 - Cheticamp
不必创建冗长的废话,只是为了在 ConstraintLayout 中让某些东西工作,最好避免使用它。 - Farid

5
我偶然发现了这个问题,并且通过Androidx.ConstraintLayout.Widget.Barrier解决了它,这是在Constraint Layout的1.1.0-beta1版本中引入的。所以我想与遇到同样问题的人分享:
<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>

目前还无法将它们水平居中,如果有人找到了解决方法,我会更新这个示例。


0
根据我对你的问题的理解,下面的代码将帮助你。
<?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>

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