如何在 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
,但它不占百分比(wrap
或 dimen
)。
我能想到的最佳解决方案是将 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 实现,带有 小 技巧,而自定义视图是一种更标准的扩展视图功能的方法。
我有两个 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
,但它不占百分比(wrap
或 dimen
)。
我能想到的最佳解决方案是将 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 实现,带有 小 技巧,而自定义视图是一种更标准的扩展视图功能的方法。