Android Jetpack Compose - 动态布局

3

背景

我目前正在研究创建布局的选项,在项目开发期间,我希望可能将UI迁移到Jetpack Compose或发布后,具体取决于库的稳定性/灵活性。

该项目的一部分将使用服务器驱动的UI。然而,有一个扭曲的地方是UI事先不知道,将是动态的(由服务器和数据驱动)。

我在处理业务逻辑和表示层方面没有问题,但是当涉及UI时,我需要根据表示数据和视图模型动态构建UI的要求。

TL;DR

考虑到这一点,是否可能使用Jetpack Compose创建动态布局(不要与动态布局数据混淆)?

作为最简示例,使用传统的ViewViewGroup可以轻松实现:

class DynamicViewActivity : AppCompatActivity() {
    
    private lateinit var root : LinearLayout

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)

        // setup view group container
        root = LinearLayout(this)
        root.orientation = LinearLayout.VERTICAL
        root.layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT, 
            LinearLayout.LayoutParams.MATCH_PARENT)
        
        setContentView(root, LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT))
        
        // some lookup to create a dynamic layout
        val children : List<Pair<View, LinearLayout.LayoutParams>> = getChildren(someArgs)
        
        // add child views
        children.forEach { (view, params) -> root.addView(view, params) }
    }
    
    fun <T : View> addViewToRoot(view: T, params: LinearLayout.LayoutParams) {
        root.addView(view, params)
    }

    fun  removeFromRoot(viewTag : String) {
        root.findViewWithTag<View>(viewTag)?.let(root::removeView)
    }
}

如何使用Jetpack Compose实现相同的功能?
更新
根据@CommonsWare的答案,我在Compose中实现了UI。由于我的实际代码具有非常薄的UI层,所有侦听器和事件都使用单向和双向数据绑定,并且答案中的“未知项”已经在我的项目中得到解决,所以只需轻松切换UI即可。
尽管如此,我很快意识到,像ScrollView和View::tooltipText这样的简单事物在Compose中尚不存在。与xml布局/资源相比,也没有简单的方法基于运行时配置(屏幕方向/屏幕桶大小等)来进行布局。这意味着对我来说,使用数据绑定与所有丰富的View框架和库仍然是更好的解决方案。
期待Compose库的更新,也许将来会看一下。

嗯,将垂直的 LinearLayout 替换为 Column(),并将 getChildren() 替换为可组合调用。换句话说,在你的示例级别上,要做的事情很少,因为你把所有复杂性都隐藏在 getChildren(someArgs) 中。 - CommonsWare
我以前从未使用过compose。对于我的用例来说,这可能是一个基本的问题。在近一个星期没有评论/回答/赞同/反对票之后,我决定冒险开启一个悬赏。我猜这要么是冷漠,要么是compose社区的曝光度有限,或者是问题提得不好。谢谢你的建议,我会仔细研究一下。 - Mark
我以前从来没有用过Compose。说实话,Compose就是一切功能。因此,如果有什么区别的话,服务器定义的用户界面更容易操作,因为你不需要处理布局的膨胀或者处理奇怪的小部件和容器的组装。使用服务器定义的用户界面,你只需要根据从服务器获取的数据调用相应的函数即可。 - CommonsWare
没问题,我明白。实际上,我正在使用一个闭源框架,该框架在底层使用了vue.js。由于没有接触过声明式UI和Compose,我对使用Compose创建即时UI有一些逻辑上的疑问。所有我见过的示例都是提前知道的UI,而我还需要处理在线/离线这样的意外情况。根据你的提示,我有一些想法可以创建某种工厂模式,返回高阶函数作为可组合项进行调用,不确定是否可行,但我会尝试一下。 - Mark
我在询问有关使用Compose创建即时UI所需的逻辑问题。你最后的问题(“如何在Jetpack Compose中实现相同效果?”)与一个明显与服务器定义的UI无关的代码示例相关联。例如,你可以展示一个根据服务器提供的对象进行不同UI构建路径分支的示例,这些路径会构建视图。然后,有人可以展示给你根据服务器提供的对象进行不同UI构建路径分支的示例,其中这些路径调用可组合项。 - CommonsWare
我明白其实我在使用一个闭源框架,底层是使用 vue.js。-- Jetpack Compose 是开源的,不基于 JavaScript。虽然 Compose for Web 可能使用了 vue.js,但这让我感到惊讶。这篇文章这篇文章,以及这个演示讨论了使用 Compose 的服务器定义 UI,尽管它们可能有点旧。 - CommonsWare
1个回答

12
针对这一点,使用Jetpack Compose是否可能创建动态布局(不要与动态布局数据混淆)? 当然可以。Compose是所有函数。您可以解析数据并基于该数据调用函数,无论该数据是“填充这个预定义的UI结构”还是该数据是“定义UI结构”。
例如,假设您的服务器具有返回以下JSON的端点:
[
  {
    "element": "label",
    "attributes": {
      // values omitted for brevity
    }
  },
  {
    "element": "field",
    "attributes": {
      // values omitted for brevity
    }
  },
  // additional elements omitted for brevity
]

你的工作是根据提供的JSON数据组装用户界面(UI)。一个

1
谢谢,这正是我在寻找的。所有“外部”范围我已经做了,事实上我一直在使用数据绑定、填充单个小部件 - 唯一缺失的就是Compose的基础知识。 - Mark
为了借鉴这个出色的答案,考虑使用Kotlin Flows或LiveData来在数据从服务器更新时自动响应状态。 - Victor Ude
现在我有一个类似的问题。我正在考虑使用访问者模式来构建不同类型的布局。 - AndroidRuntimeException

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接