如何在 ConstraintLayout 中设置 View 的最小百分比宽度

How to set minimum percentage width of View in a ConstraintLayout

我有两个 Button 排成一排 ContraintLayout。默认情况下,我需要它们均匀分布,每个占 ConstraintLayout 宽度的 50%(将垂直 Guideline 设置为 50% 就足够了):

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

  ...
  
  <Button
      android:id="@+id/secondaryButton"
      style="@style/Button.Secondary"
      android:text="Secondary Button"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toStartOf="@id/primaryButtonBarrier"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@id/detail" />

  <Button
      android:id="@+id/primaryButton"
      style="@style/Button.Primary"
      android:layout_width="0dp"
      android:text="Primary Button"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toEndOf="@id/middleGuideline"
      app:layout_constraintHorizontal_bias="1.0"
      app:layout_constraintTop_toBottomOf="@id/detail" />

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

  <androidx.constraintlayout.widget.Barrier
      android:id="@+id/primaryButtonBarrier"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:barrierDirection="start"
      app:constraint_referenced_ids="primaryButton, middleGuideline"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintTop_toBottomOf="@id/detail" />

</androidx.constraintlayout.widget.ConstraintLayout>

期望的行为(目前通过以下代码片段以编程方式实现):

我还需要在右侧的主要 Button 中支持“溢出”文本。

因此,如果我有大量文本,Button 宽度将超过 50% 的准则。我试过使用 app:layout_constraintWidth_min,但它不占百分比(wrapdimen)。

我能想到的最佳解决方案是将 Button 宽度设置为 wrap_content,然后在测量 ConstraintLayout 后以编程方式设置最小宽度:

doOnLayout { constraintLayout -> 
    val layoutParams = primaryButton.layoutParams as ConstraintLayout.LayoutParams
    layoutParams.matchConstraintMinWidth = constraintLayout.measuredWidth / 2
    primaryButton.layoutParams = layoutParams
}

我觉得这里必须有一个我缺少的设置组合才能实现这一点。提前致谢!

没有直接的方法可以使用任何标准 XML 代码和标准 ConstraintLayout 属性来完成我所知道的事情。您也许可以使用嵌套布局来做一些事情,但一般来说,应该避免使用 ConstraintLayout。我认为您设计的方式可能会是可行的方式。

但是,如果您想在 XML 中完成这一切,您可以创建一个阴影按钮,它在所有方面(位置、样式、文本等)都是主按钮的副本,除了它是看不见的。然后可以在阴影按钮和中心参考线的左侧放置一个屏障。可见的主按钮现在可以限制在屏障上,因为屏障不依赖于主按钮。主按钮至少是 ConstraintLayout 宽度的 1/2,但可以超出。

第二种方法是为主按钮创建自定义视图。此自定义视图可以实现一个属性,该属性根据 ConstraintLayout.

的宽度指定按钮的最小宽度

ButtonMinWidthOfParent.kt

class ButtonMinWidthOfParent @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : MaterialButton(context, attrs) {

    private var minWidthOfParent = 0f

    init {
        context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.ButtonMinWidthOfParent,
            0, 0
        ).apply {
            try {
                minWidthOfParent = getFloat(R.styleable.ButtonMinWidthOfParent_minWidthOfParent, 0f)
            } finally {
                recycle()
            }
        }
    }

    @Override
    override fun getSuggestedMinimumWidth(): Int {
        return maxOf(
            super.getSuggestedMinimumWidth(),
            ((parent as ViewGroup).measuredWidth * minWidthOfParent).toInt()
        )
    }
}

attrs.xml

<resources>
    <declare-styleable name="ButtonMinWidthOfParent">
        <attr name="minWidthOfParent" format="float"/>
    </declare-styleable>
</resources>

activity_main

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

    <View
        android:id="@+id/detail"
        android:layout_width="0dp"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/secondaryButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Secondary Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/primaryButton"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/detail" />

    <com.example.secondarybutton.ButtonMinWidthOfParent
        android:id="@+id/primaryButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Primary Button that is a little bit longer"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/detail"
        app:minWidthOfParent="0.5" />

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

    <View
        android:id="@+id/view"
        android:layout_width="2dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_red_light"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

毫无疑问还有其他方法,但是 XML 方法的优点是它是纯 XML 实现,带有 技巧,而自定义视图是一种更标准的扩展视图功能的方法。