【问题标题】:Does Compose ConstraintLayout provide same handling for INVISIBLE and GONE as view based ConstraintLayout?Compose ConstraintLayout 是否为 INVISIBLE 和 GONE 提供与基于视图的 ConstraintLayout 相同的处理?
【发布时间】:2020-08-28 17:53:06
【问题描述】:

免责声明:我知道 Compose 刚刚输入 alpha01,因此我不希望所有功能 可用。但是,特定布局案例的布局和处理是恕我直言的一个重要主题 应该尽早解决????。

当前基于视图 ConstraintLayout 提供了一些特定的处理,以防子视图 标记为GONE,请参阅 ConstrainLayout documentation.

我检查了 Compose ConstraintLayout 文档、可用的修饰符等,但是 没有找到任何指向这个方向的东西。我也找不到任何关于 INVISIBLE 以及如何/如果 Compose ConstraintLayout基于视图 ConstraintLayout 那样处理它。

一般来说,当前基于视图的布局(例如LinearLayout)处理INVISIBLEGONE在一个 类似的时尚:

  • 如果视图处于INVISIBLE 状态,那么该视图是布局的一部分及其大小,而不是 显示。其他视图的整体布局没有改变,保持在原来的位置。

  • 如果视图处于GONE 状态,则其大小通常被视为 0,并且重新计算布局并 改变了,其他视图通常会改变它们的位置。

这里是一个简单的 Compose ConstraintLayout UI,只有 4 个连续的按钮,链接起来很好 传播。

// if dontShow is 0 then show all buttons, otherwise make the button with this number
// somehow INVISIBLE. This feature is not yet implemented.
@Composable
fun fourButtonsCL(dontShow: Int) {
    ConstraintLayout(Modifier.fillMaxSize()) {
        val (btn1, btn2, btn3, btn4) = createRefs()
        TextButton(onClick = {}, Modifier.constrainAs(btn1) {}.background(teal200)) { Text("Button1") }
        TextButton(onClick = {}, Modifier.constrainAs(btn2) {}.background(teal200)) { Text("Button2") }
        TextButton(onClick = {}, Modifier.constrainAs(btn3) {}.background(teal200)) { Text("Button3") }
        TextButton(onClick = {}, Modifier.constrainAs(btn4) {}.background(teal200)) { Text("Button4") }

        createHorizontalChain(btn1, btn2, btn3, btn4)
    }
}

@Preview(showBackground = true)
@Composable
fun previewThreeButtons() {
    ComposeAppTheme {
        fourButtonsCL()
    }
}

假设我想让Button3 不可见,但将其他 3 个按钮保持在它们所在的位置 是。因此,Button2Button4 之间只有一个洞。如何在不创建另一个的情况下实现这一目标 可组合或添加额外的逻辑。虽然这个简单案例中的逻辑可能只是一个视图线 代码,更复杂的布局将需要一些更复杂的逻辑。基于视图的 ConstraintLayout 我们只需要修改子视图。

另一个假设:使Button3从布局中完全消失(GONE)并重新计算 布局,剩余的按钮变得更宽并均匀分布。乍一看,这看起来很简单, 在这个非常简单的例子中,它可能很容易。然而,在更复杂的布局中,这可能需要 嵌入式 Composables 的一些甚至很多约束的重新布线。

因此问题是: compose 如何为ColumnRow 布局处理这些情况(如基于视图的LinearLayout) 特别是ConstraintLayout?但是有以下限制??????:没有定义 许多新的 Composables 和/或没有在 Composables 中添加复杂的布局逻辑(重新布线 例如约束)。

我错过了一些修饰符吗?这在可组合布局中是否计划或可能?会是什么 在 Compose 中解决此类布局案例的首选方法是什么?

【问题讨论】:

  • “不可见”和“消失”在 Compose UI 中并不是真正的东西。 “消失”是您根本不将元素包含在您的合成中,并且您负责该场景的规则以及该元素在合成中的情况。根据您的情况,“不可见”可能会使用Spacer() 或其他一些透明替代常规元素来构建组合。我不认为 Modifier 会导致隐身,因为 Modifier 装饰可组合的东西多于改变它。
  • 这就是我的想法/恐惧。在复杂的布局上,这需要编程逻辑来排除元素、重新连接约束等。我已经测试过了,它很丑。我还使用了不同的 Composables 来避免复杂的编程逻辑,但这会导致大量的代码重复。将视图设置为 GONE 或 INVISIBLE 的简单语句现在变成了一项真正复杂的任务。
  • 由于 Compose 可能需要一年多的时间才能以稳定的形式发布,所以我不会从当前的 alpha 中得出任何长期结论。关于“不可见”,我可能过于悲观:尝试Modifier.drawOpacity()0f 看看是否会使可组合透明化。
  • 谢谢。 drawOpacity(0f) 至少对简单的测试用例起到了作用。

标签: android android-jetpack-compose


【解决方案1】:

基于@CommonsWare 对我可以解决INVISIBLE 的问题的评论 选项,请参见下面的代码。

目前(在 alpha-01 中)ConstraintLayout 的实现似乎不完整,代码中至少有几个 TODO cmets 表明了这一点。这 似乎包括对GONE 功能的尚未支持。 我看到了其中的一些:

// TODO(popam, b/158069248): 为消失的边距添加参数

此外,链功能还没有以与相同的方式执行布局渲染 在基于视图的 ConstraintLayout 中。

object FourElementsNoDSL {
    const val elementA = "ElementA"
    const val elementB = "ElementB"
    const val elementC = "ElementC"
    const val elementD = "ElementD"

    private val noDSLConstraintSet = ConstraintSet {

        // Create references with defines ids, here using a string as id. Could be an Int as well,
        // actually it's defined as 'Any'
        val elemA = createRefFor(elementA)
        val elemB = createRefFor(elementB)
        val elemC = createRefFor(elementC)
        val elemD = createRefFor(elementD)

        // Simple chain only. Instead of this simple chain we can use (for example):
        //     constrain(elemA) {start.linkTo(parent.start) }
        // to set a constraint as known in XML

//        constrain(elemA) {start.linkTo(parent.start, 16.dp) }
//        constrain(elemB) {start.linkTo(elemA.end) }
//        constrain(elemC) {start.linkTo(elemB.end) }
//        constrain(elemD) {end.linkTo(parent.end) }
        createHorizontalChain(elemA, elemB, elemC, elemD)
    }

    @Composable
    fun fourButtonsCLNoDSL(doNotShow: List<String>) {
        ConstraintLayout(constraintSet = noDSLConstraintSet, modifier = Modifier.fillMaxSize()) {

            // This block contains the children
            Text(text = "A",
                    modifier = Modifier.layoutId(elementA)
                            .drawOpacity(if (doNotShow.contains(elementA)) 0f else 1f)
                            .padding(0.dp),
                    style = TextStyle(fontSize = 20.sp)
            )
            Text(text = "B",
                    modifier = Modifier.layoutId(elementB)
                            .drawOpacity(if (doNotShow.contains(elementB)) 0f else 1f)
                            .padding(0.dp),
                    style = TextStyle(fontSize = 20.sp)
            )
            Text(text = "C",
                    modifier = Modifier.layoutId(elementC)
                            .drawOpacity(if (doNotShow.contains(elementC)) 0f else 1f)
                            .padding(0.dp),
                    style = TextStyle(fontSize = 20.sp)
            )
            Text(text = "D",
                    modifier = Modifier.layoutId(elementD)
                            .drawOpacity(if (doNotShow.contains(elementD)) 0f else 1f)
                            .padding(0.dp),
                    style = TextStyle(fontSize = 20.sp))

        }
    }
}

@Preview(showBackground = true)
@Composable
fun previewFourFieldsNoDSL() {
    val noShow = listOf(FourElementsNoDSL.elementC)
    PlaygroundTheme {
        FourElementsNoDSL.fourButtonsCLNoDSL(noShow)
    }
}

object FourElementsNoDSL 定义布局,提供元素 ID 等等。 这与包含此类布局的 XML 文件大致相当。 noDSL 表示,这个布局没有使用 Compose ConstraintLayout 的 Kotlin DSL。目前 DSL 不提供设置元素引用的机制 (在layoutId 中使用)具有定义的ID,如本例中所做的那样。

【讨论】:

    猜你喜欢
    • 2017-09-26
    • 2022-11-01
    • 2021-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多