通过ComposeView互操作,在CoordinatorLayout内部组合LazyColumn滚动行为

16

问题 - 向下滚动会导致底部表单滚动而不是优先给予LazyColumn滚动(RecyclerView没有这个问题。它被NestedScrollView包装)

我刚刚在CoordinatorLayout中引入了Compose LazyColumn替换Recycler。Coordinator(作为底部表单实现)可以在收起和展开状态之间自由滚动。我的问题是,在LazyColumn中向下拖动项目区域时,底部表单会接替滚动而不是LazyColumn。如果我先向上滚动,然后再向下滚动(没有释放),则LazyColumn会接替滚动,并且滚动优先级会给予LazyColumn(预期行为)。

BottomSheetFragment
|-CoordinatorLayout
|--ConstraintLayout (BottomSheetBehavior)
|---MyListFragment
|----ComposeView
|-----Theme
|------Surface
|-------Box
|--------LazyColumn

我刚开始使用Compose,希望有人告诉我如何解决这种新的滚动行为?

**编辑 通过切换Coordinator的^^ BottomSheetBehavior.isDragglable,我已经部分实现了这个功能,但需要释放拖动而不是平稳地从列表滚动到底部表单滚动 - 有人能建议一个修复方法吗?

fun MyUi(listener:Listener) {
    val listState = rememberLazyListState()

    LaunchedEffect(listState) {
        listState.interactionSource.interactions.collect {
            //at the top of the list so allow sheet scrolling
            listener.allowSheetDrag(listState.firstVisibleItemScrollOffset == 0)
        }
    }

    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                Timber.i("NestedScrollConnection onPreScroll($available: Offset, $source: NestedScrollSource)")
                return super.onPreScroll(available, source)
            }

            override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
                Timber.i("NestedScrollConnection onPostScroll($consumed: Offset, $available: Offset, $source: NestedScrollSource)")
                if (available.y > 0.0 && consumed.y == 0.0f) {
                    //scolling down up but we're already at the top - kick over to sheet scrolling
                    listener.allowSheetDrag(true)
                }
                return super.onPostScroll(consumed, available, source)
            }
        }
    }
    Box(
        modifier = Modifier
            .fillMaxSize()
            .nestedScroll(nestedScrollConnection)
    ) {
        LazyColumn(
            modifier =
            Modifier
                .fillMaxSize()
                .padding(vertical = 12.dp), state = listState
        ) {
            item {
                Row() {}
            }
        }
    }
}

然后在Fragment中:

override fun allowSheetDrag(allowSheetDrag: Boolean) {
    bottomSheetFragment?.bottomSheetBehavior?.isDraggable = allowSheetDrag
}

如果LazyColumn没有任何项在其上方(即已经显示第一项),并且您向下滚动(拖动),则应该由父滚动容器接收滚动。这正是您在第一个案例中观察到的情况。 - Om Kumar
1
@SteffenFunke 我今天刚开始重新研究这个问题 - 这是我集成我们的第一个Compose UI时唯一阻碍我的问题。我开始研究使用自定义底部表现行为来解决这个问题(我对协调器/表等大多数不熟悉)。 - jchristof
1
@SteffenFunke,请查看我的部分解决方案。如果您能将其推进到从列表到底部工作表的平滑滚动,请告诉我。 - jchristof
1
@jchristof 谢谢你回复!我一回到项目就会试一试。保持联系。 - Steffen Funke
对于任何感兴趣的人,我已经将一个示例推送到了 GitHub 上:https://github.com/sfunke/bottomsheetdialogfragment_compose_interop - Steffen Funke
显示剩余5条评论
2个回答

26

巫师Chris Banes最近发布了一个解决方法,我可以确认它有效。

当在 BottomSheetDialog 中使用时,它也可以流畅地过渡而无需动手(向上滚动,然后一气呵成地将表单向下拖)。

示例用法 (取自Chris Banes的示例):

setContent {
    Surface(
        // Add this somewhere near the top of your layout, above any scrolling layouts
        modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())
    ) {
        LazyColumn() {
            // blah
        }
    }
}

正在跟踪一个有关ComposeViews嵌套滚动的问题:https://issuetracker.google.com/issues/174348612,以及一个相关的Stack Overflow问题,它让我去了那里:AndroidView在NestedScrollView中失去触摸事件


6
很遗憾,XML和Compose之间的可滚动交互性不是很好。View有一个名为isNestedScrollingEnabled()的方法,而Compose始终返回false,因此嵌套滚动具有不可预测的行为(我认为您在这里所描述的就是这种情况)。
解决该问题的方法是确保对于可以滚动超出全屏幕的内容,将BottomSheet放置在BottomSheetScaffold或其他自定义的Compose视图中。目前来看,您可能需要在整个体验中转换为Compose,才能按照我们期望的方式工作。
同时,Compose也一直在不断地发展改进。这些评论适用于Compose 1.0.4和Material Design库1.3.0,但未来可能会有所改变。

感谢您提供有关嵌套滚动属性的提示 - 这几乎可以完全解决我的问题,但我还没有找到如何在不释放并再次滚动的情况下将滚动无缝传输到底部工作表。可能有一种方法可以从工作表中消耗拖动事件,并将它们指向LazyColumn,直到该列已达到其滚动的末尾(或顶部)。 - jchristof
isNestedScrollingEnabled() 似乎可以做到这一点,但是更改启用值直到开始新的滚动才会生效。 - jchristof
请注意,在@jchristofs的问题下,我留言了一个在GitHub上拼凑出来但可行的解决方案。不过,你仍然需要抬起手指。不幸的是,尝试使用“isNestedScrollingEnabled”并没有成功。但至少,我的安卓设备上有一些页面(例如应用抽屉)表现相同,所以¯_(ツ)_/¯。 - Steffen Funke

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