【问题标题】:Is it possible to have single Android ConstraintLayout configurable Horizontal or Vertical Orientation?是否可以有单个 Android ConstraintLayout 可配置的水平或垂直方向?
【发布时间】:2020-04-13 19:31:26
【问题描述】:

我想用 ConstraintLayout 编写一个可重用的自定义视图,并且只有 1 个布局文件(如果可能)。我想要一个相当“简单”的垂直或水平排列的 3 个按钮,基于自定义视图上的方法,例如“setVertical()”,默认为水平等。

我显然可以使用不同的布局文件来做到这一点,但我更喜欢更干净的单文件解决方案。

这可能吗?如果可以,怎么做?

这会通过 AttributeSet 完成吗?

【问题讨论】:

  • 不,没有像约束布局中的实用程序这样简单的方向更改,您必须为水平情况动态添加更改约束,对于垂直情况也是如此,但在这些按钮中,您可以使用链控制它们的传播在约束布局中,检查下面的链接medium.com/@nomanr/constraintlayout-chains-4f3b58ea15bb

标签: android android-layout android-constraintlayout


【解决方案1】:

正如有人在评论中所说,您不能直接执行此操作。您必须手动更改 ConstraintLayout 上的约束以更改方向。这是我设法做到的:

自定义视图类:

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

    var orientation = -1
        set(value) {
            if (field == value) return
            field = value

            val constraints = ConstraintSet()
            constraints.clone(this)
            when (orientation) {
                HORIZONTAL -> {
                    constraints.createHorizontalChainRtl(ConstraintSet.PARENT_ID, ConstraintSet.START, ConstraintSet.PARENT_ID,
                            ConstraintSet.END, CHAIN_IDS, null, ConstraintSet.CHAIN_SPREAD)
                    for (id in CHAIN_IDS) {
                        constraints.centerVertically(id, ConstraintSet.PARENT_ID)
                    }
                }
                VERTICAL -> {
                    constraints.createVerticalChain(ConstraintSet.PARENT_ID, ConstraintSet.TOP, ConstraintSet.PARENT_ID,
                            ConstraintSet.BOTTOM, CHAIN_IDS, null, ConstraintSet.CHAIN_SPREAD)
                    for (id in CHAIN_IDS) {
                        constraints.centerHorizontallyRtl(id, ConstraintSet.PARENT_ID)
                    }
                }
                else -> error("Invalid orientation")
            }
            constraints.applyTo(this)
        }

    init {
        View.inflate(context, R.layout.custom_view, this)
        orientation = HORIZONTAL
    }

    companion object {
        const val HORIZONTAL = 0
        const val VERTICAL = 1

        val CHAIN_IDS = intArrayOf(R.id.btn1, R.id.btn2, R.id.btn3)
    }
}

R.layout.custom_view 文件:

<merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
    <Button android:id="@+id/btn1" android:layout_width="48dp" android:layout_height="48dp"/>
    <Button android:id="@+id/btn2" android:layout_width="48dp" android:layout_height="48dp"/>
    <Button android:id="@+id/btn3" android:layout_width="48dp" android:layout_height="48dp"/>
</merge>

这将使用ConstraintSet 创建一个带有 3 个按钮的水平或垂直展开链。也就是说,如果您只需要三个按钮,您可能只需更改其方向即可使用 LinearLayout 获得相同的结果。

【讨论】:

  • 谢谢。布局更复杂,我知道如何做它的其他部分,所以我把所有这些都省略了。我只是不确定这是否“真的”可行,或者只有两个布局会更干净,等等。
  • 如果您计划在通货膨胀后支持更改,那么这个解决方案可能是值得的,否则我建议您保持简单并有两种布局。您可以在每个布局中只保留约束,将其余部分抽象为样式。那会很干净。在我看来,以编程方式设置约束并不是很干净。
猜你喜欢
  • 2017-08-24
  • 2012-04-20
  • 1970-01-01
  • 2021-12-04
  • 2016-10-26
  • 1970-01-01
  • 1970-01-01
  • 2020-09-19
  • 2018-02-16
相关资源
最近更新 更多