BottomSheetDialogFragment 内 LazyColumn 的滚动问题

Mik*_*ike 16 android scroll bottom-sheet android-jetpack-compose lazycolumn

我使用LazyColumninside BottomSheetDialogFragment,但如果LazyColumn向上滚动列表,则Bottom工作表对话框将滚动而不是LazyColumn列表。似乎BottomSheetDialogFragment拦截用户触摸输入。

看起来就是这样:

LazyColumn里面如何正确使用BottomSheetDialogFragment

MyBottomSheetDialogFragment.kt:

class MyBottomSheetDialogFragment : BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            setContent {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text("Header", color = Color.Black)
                    LazyColumn(
                        Modifier
                            .weight(1f)
                            .fillMaxWidth()) {
                        items(100) {
                            Text("Item $it", Modifier.fillMaxWidth(), Color.Black)
                        }
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用以下代码显示它:

MyBottomSheetDialogFragment().show(activity.supportFragmentManager, null)
Run Code Online (Sandbox Code Playgroud)

当我们使用 XMLRecyclerView列表时,要解决这个问题,我们必须使用此处描述的方式包装RecyclerView列表,但是如何使用 Jetpack Compose 解决它?NestedScrollView

ikn*_*now 23

由于组合问题可以通过使用RememberNestedScrollInteropConnection1.2.0-beta01来解决 :

Modifier.nestedScroll(rememberNestedScrollInteropConnection())
Run Code Online (Sandbox Code Playgroud)

就我而言,它BottomSheetDialogFragment是标准的View,并且带有ComposeViewid container。在onViewCreated我做的:

binding.container.setContent {
    AppTheme {
        Surface(
            modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())
        ) {
            LazyColumn {
                // ITEMS
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在列表正在以正确的方式滚动。

  • 当我尝试向下拖动以关闭底页时,底页顶部没有响应,这是预期的行为吗?(我在 LazyColumn 上方有一个 Text-composable) (7认同)

Mik*_*ike 1

我找到了这个问题的一个很好的答案。我们可以使用 Kotlin 扩展在 Android 视图上使用 Jetpack Compose 底部工作表。

有关其工作原理的更多详细信息请参见此处

这是我们需要的所有代码:

// Extension for Activity
fun Activity.showAsBottomSheet(content: @Composable (() -> Unit) -> Unit) {
    val viewGroup = this.findViewById(android.R.id.content) as ViewGroup
    addContentToView(viewGroup, content)
}

// Extension for Fragment
fun Fragment.showAsBottomSheet(content: @Composable (() -> Unit) -> Unit) {
    val viewGroup = requireActivity().findViewById(android.R.id.content) as ViewGroup
    addContentToView(viewGroup, content)
}

// Helper method
private fun addContentToView(
    viewGroup: ViewGroup,
    content: @Composable (() -> Unit) -> Unit
) {
    viewGroup.addView(
        ComposeView(viewGroup.context).apply {
            setContent {
                BottomSheetWrapper(viewGroup, this, content)
            }
        }
    )
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun BottomSheetWrapper(
    parent: ViewGroup,
    composeView: ComposeView,
    content: @Composable (() -> Unit) -> Unit
) {
    val TAG = parent::class.java.simpleName
    val coroutineScope = rememberCoroutineScope()
    val modalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
    var isSheetOpened by remember { mutableStateOf(false) }

    ModalBottomSheetLayout(
        sheetBackgroundColor = Color.Transparent,
        sheetState = modalBottomSheetState,
        sheetContent = {
            content {
                // Action passed for clicking close button in the content
                coroutineScope.launch {
                    modalBottomSheetState.hide() // will trigger the LaunchedEffect
                }
            }
        }
    ) {}

    BackHandler {
        coroutineScope.launch {
            modalBottomSheetState.hide() // will trigger the LaunchedEffect
        }
    }

    // Take action based on hidden state
    LaunchedEffect(modalBottomSheetState.currentValue) {
        when (modalBottomSheetState.currentValue) {
            ModalBottomSheetValue.Hidden -> {
                when {
                    isSheetOpened -> parent.removeView(composeView)
                    else -> {
                        isSheetOpened = true
                        modalBottomSheetState.show()
                    }
                }
            }
            else -> {
                Log.i(TAG, "Bottom sheet ${modalBottomSheetState.currentValue} state")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)