4

问题 - 向下滚动会导致底部工作表滚动而不是将滚动优先级赋予 LazyColumn(RecyclerView 没有这个问题。它被 NestedScrollView 包裹)

我刚刚在 CoordinatorLayout 中引入了一个 Compose LazyColumn 替换 Recycler。Coordinator(作为底部工作表实现)本身可以在查看和展开状态之间自由滚动。我的问题是在 LazyColumn 中向下拖动项目区域时,底部工作表会拾取滚动而不是 LazyColumn 。如果我在 LazyColumn 上先向上然后向下滚动(不释放),则滚动由 LazyColumn 拾取,滚动优先级赋予 LazyColumn(预期行为。)

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

Compose 新手,所以我希望有人能告诉我如何纠正这种新的滚动行为?

**编辑 我正在通过切换协调器的 ^^ 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() {}
            }
        }
    }
}

然后在片段中:

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

2 回答 2

7

Wizard Chris Banes 最近发布了一个解决方法,我可以确认它有效:https ://gist.github.com/chrisbanes/053189c31302269656c1979edf418310

当在 a 内部使用时,它也无需抬起手指即可很好地过渡BottomSheetDialog(向上滚动,然后一次将工作表向下拖动)

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

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

使用 ComposeViews 跟踪嵌套滚动存在一个问题:https ://issuetracker.google.com/issues/174348612和一个相关的 SO 问题导致我到达那里:AndroidView in Compose lost touch events in NestedScrollView

于 2021-12-02T07:39:49.280 回答
2

不幸的是,XML 和 Compose 之间的可滚动互操作性不是很好。View 上有一个名为 isNestedScrollingEnabled() 的方法,而 Compose 总是返回 false,因此嵌套滚动具有不可预测的行为(我相信您在此处描述了这一点)。

我发现的解决方法是确保对于可以滚动大于全屏的内容,您将 BottomSheet 放置在 BottomSheetScaffold 或其他自定义 Composable 视图中。就目前而言,您可能需要将整个体验转换为 Compose,然后它才能以我们期望的方式工作。

Compose 也在不断发展。这些评论对于 Compose 1.0.4 和 Material Design library 1.3.0 是准确的——它可能会在未来发生变化。

于 2021-11-10T04:53:39.807 回答