android 在ConstraintLayout中强制统一按钮大小

xqk2d5yq  于 2023-01-19  发布在  Android
关注(0)|答案(1)|浏览(175)

我有一个ConstraintLayout,它包含了许多元素,包括网格布局中的几个按钮,下面是布局的简化版本(实际布局包含了额外的元素):

<androidx.constraintlayout.widget.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">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 1"
        app:layout_constraintBottom_toTopOf="@+id/button3"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar" />

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 2"
        app:layout_constraintBottom_toTopOf="@+id/button4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/button1"
        app:layout_constraintTop_toBottomOf="@+id/toolbar" />

    <Button
        android:id="@+id/button3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 3"
        app:layout_constraintBottom_toTopOf="@id/guideline"
        app:layout_constraintEnd_toStartOf="@+id/button4"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button1" />

    <Button
        android:id="@+id/button4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 4"
        app:layout_constraintBottom_toTopOf="@id/guideline"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/button3"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

</androidx.constraintlayout.widget.ConstraintLayout>

我希望按钮的大小满足两个条件:
1.每个按钮都应该包含其所有文本,没有任何文本被截断或省略
1.所有按钮的大小应相同
换句话说,每个按钮的大小应该等于任何按钮的最大文本的大小,在ConstraintLayout中可以做到这一点吗?
我可以通过设置满足第一个条件(如上面的XML所示)将按钮宽度和高度分别设置为odpwrap_content,这适用于所有按钮文本大小相同的特定情况(如上面的XML和我的应用程序的原始(英语)版本),但如果它们不是(例如,如果Button 4 plus several extra words被替换为Button 4,以及我的应用程序的至少一个翻译中发生的情况),那么按钮大小和对齐方式将失去对称性和均匀性。
我想坚持使用ConstraintLayout,最好不要在其中嵌套另一个布局,因为这似乎是目前推荐的方式,但我想如果有必要的话,我可以切换。我已经尝试了here的一些想法,但我无法让它们在我的情况下工作,正如我所说,如果可能的话,我真的宁愿坚持使用纯ConstraintLayout

kcrjzv8t

kcrjzv8t1#

如果按钮一个在另一个之上或并排堆叠(如here所述),则有一些解决方案。但是,尚不清楚此类解决方案是否公开了受支持的行为,或者只是公开了在实现 * ConstraintLayout * 时发生问题的方式。无论如何,您面临的问题是如何在网格中将所有按钮的大小调整为最宽。
您需要对布局中的按钮进行显式调整,您可以使用layout change listener在代码中以编程方式进行调整。
另一种方法是使用从ConstraintHelper类派生的类来调整按钮大小。该类是一些 * ConstraintLayout * 小部件(如 * Barriers *)的基础。派生的小部件可以直接放入布局XML中。
下面是一个示例:

class GreatestWidthHelper @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {

    override fun updatePostLayout(container: ConstraintLayout) {
        var maxWidth = 0
        val referencedViews = mutableListOf<View>()

        // Find the greatest width of the referenced widgets.
        for (i in 0 until this.mCount) {
            val id = this.mIds[i]
            val view = container.getViewById(id)
            if (view.width > maxWidth) {
                maxWidth = view.width
            }
            referencedViews.add(view)
        }

        // Set the width of all referenced view to the width of the view with the greatest width.
        for(view in referencedViews) {
            if (view.width != maxWidth) {
                view.layoutParams.width = maxWidth
                view.requestLayout()
            }
        }
    }
}

我已经将这个小部件放到XML中,并做了一些其他的调整。

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="Button 1"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toTopOf="@+id/button3"
        app:layout_constraintEnd_toStartOf="@+id/centerGuideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="Button 2"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toTopOf="@+id/button4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/centerGuideline"
        app:layout_constraintTop_toBottomOf="@+id/toolbar" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="Button 3"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toTopOf="@id/guideline"
        app:layout_constraintEnd_toStartOf="@+id/centerGuideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button1" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="Button 4 Longer"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toTopOf="@id/guideline"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/centerGuideline"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <com.example.starterapp.GreatestWidthHelper
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="button1,button2,button3,button4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/centerGuideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

</androidx.constraintlayout.widget.ConstraintLayout>

小部件将能够在Android Studio设计器中进行调整。

但是在模拟器中看起来还可以。

并且在按钮的文本被强制换行时将执行。

helper类可以进一步增强,以考虑视图的高度。

class GreatestSizeHelper @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {

    override fun updatePostLayout(container: ConstraintLayout) {
        var maxWidth = 0
        var maxHeight = 0
        val referencedViews = mutableListOf<View>()

        // Find the greatest width of the referenced widgets.
        for (i in 0 until this.mCount) {
            val id = this.mIds[i]
            val view = container.getViewById(id)
            if (view.width > maxWidth) {
                maxWidth = view.width
            }
            if (view.height > maxHeight) {
                maxHeight = view.height
            }
            referencedViews.add(view)
        }

        // Set the width of all referenced view to the width of the view with the greatest width.
        for (view in referencedViews) {
            if (view.width != maxWidth || view.height != maxHeight) {
                view.layoutParams.width = maxWidth
                view.layoutParams.height = maxHeight
                view.requestLayout()
            }
        }
    }

}

相关问题