Jetpack Compose 中的垂直嵌套滚动

Vertical nested scroll in Jetpack Compose

最近,我在使用 100% compose! 的应用程序中开发一项功能时撞墙了。我正在尝试实现垂直嵌套滚动视图。我的情况是我正在查看 edit/create 锻炼。这些被分成不同的组,里面有一个练习列表。

想法是有一个卡片列表,里面有一个项目(练习)列表()。

当我尝试构建视图时,出现了下一个错误:

java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like ScrollableContainer and LazyColumn is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().

我知道它不受支持,我想问的是是否有任何我可以做的解决方法。代码如下所示:

    LazyColumn(Modifier.fillMaxSize()) {
    itemsIndexed(workout.workoutSets) { setIndex, workoutSet ->

        //State that contains the re-order drag & drop and calls the original list to be modified in my VM
        val state: ReorderableState = rememberReorderState(onMove = { from, to ->
            Grove.e { "Moving from $from to $to" }
            if (to <= workoutSet.exercises.lastIndex) {
                onExerciseMoved(setIndex, from, to)
            }
        })

        LazyColumn(
            state = state.listState,
            modifier = Modifier
                .fillMaxWidth()
                .reorderable(state) //Modifier that allows the drad&drop in this container
        ) {
            itemsIndexed(items = workoutSet.exercises, itemContent = { index, item ->
                Box(
                    Modifier
                        .fillMaxWidth()
                        .draggedItem(state.offset.takeIf { state.index == index }) //The dragged item modifier
                        .scale(if (state.index == null || state.index == index) 1f else .9f)
                ) {
                    CreatorExerciseItemRow(
                        onExerciseClick = { onExerciseClick(item) },
                        execution = item
                    )
                }
            })
        }
    }
}

您可以从库中找到我正在使用的拖放代码(不是我的)here

最后让您了解我想要实现的目标。屏幕看起来像:

我的想法是,我可以 long-press 练习并将它们拖放到各自的卡片上。但同时允许屏幕变高并在需要时垂直滚动。现在,我只需将上面代码中的第一个 LazyColumn 替换为 repeat/foreach 即可正常工作。但是很快我的列表就变大了,视图被隐藏了。

您可以使用单个普通列表并根据类型绘制内容。

首先,您应该将数据转换为一个简单的列表(当然,这是一个伪代码)。

val plainList = mutableListOf<Any>()
worksets.forEach {
    plainList.add(it)
    it.exercises.forEach{
        plainList.add(it)
    }
}

然后,在您的 LazyColumn 中,您根据项目类型绘制项目。

LazyColumn(Modifier.fillMaxSize()) {
    items(plainList) { item ->
        when (item) {
            is Workset -> WorkSetHeaderItem(item)
            is Exercise -> ExerciseItem(item)
        }
    }
}

恐怕不可能。

据我了解,您可以限制在不同集合之间移动的项目。

您可以获取 ComposeReorderable 的源代码并为您的任务应用所需的更改。代码不多(我喜欢编写),所以应该不会太难。完成后甚至可以提交拉取请求,因为这样的功能可能对其他人有用。