You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ModalNavigationDrawer嵌套带SwipeToDismissBox的LazyColumn侧滑冲突问题

解决ModalNavigationDrawer嵌套SwipeToDismissBox的手势冲突问题

可以实现类似Gmail的效果,核心是解决手势优先级冲突——SwipeToDismissBox默认会拦截所有侧滑手势,哪怕禁用了某个方向,也会抢占边缘区域的抽屉触发手势。下面是具体实现方案:

核心思路

通过区分屏幕边缘区域和列表项内容区域,让边缘区域的侧滑手势优先交给ModalNavigationDrawer处理,非边缘区域的手势则由SwipeToDismissBox处理。

具体实现代码

@Composable
fun DrawerWithSwipeableList() {
    val drawerState = rememberDrawerState(DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    // 定义触发抽屉的边缘宽度(可根据需求调整)
    val drawerEdgeWidth = 24.dp
    val density = LocalDensity.current

    ModalNavigationDrawer(
        drawerState = drawerState,
        drawerContent = {
            // 抽屉内容示例
            Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
                repeat(5) { Text("Drawer Item $it", modifier = Modifier.padding(8.dp)) }
            }
        },
        content = {
            LazyColumn(
                modifier = Modifier.interceptTouchEvent { motionEvent ->
                    // 在触摸按下阶段判断是否属于抽屉触发区域
                    if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                        val touchX = motionEvent.x
                        with(density) {
                            // 边缘区域:不拦截,交给抽屉处理
                            return@interceptTouchEvent touchX > drawerEdgeWidth.toPx()
                        }
                    }
                    true
                }
            ) {
                items(50) { index ->
                    val swipeState = rememberSwipeToDismissBoxState(
                        confirmValueChange = {
                            // 处理列表项删除逻辑
                            true
                        }
                    )

                    SwipeToDismissBox(
                        state = swipeState,
                        enableDismissFromStartToEnd = false,
                        enableDismissFromEndToStart = true,
                        backgroundContent = {
                            // 侧滑删除背景(比如红色删除提示)
                            Box(
                                modifier = Modifier.fillMaxSize().background(Color.Red),
                                contentAlignment = Alignment.CenterEnd
                            ) {
                                Text("删除", color = Color.White, modifier = Modifier.padding(16.dp))
                            }
                        }
                    ) {
                        // 列表项内容
                        Card(
                            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
                            elevation = CardDefaults.cardElevation(4.dp)
                        ) {
                            Text(
                                "列表项 $index",
                                modifier = Modifier.fillMaxWidth().padding(16.dp)
                            )
                        }
                    }
                }
            }
        }
    )
}

关键逻辑说明

  1. 边缘区域判断:通过Modifier.interceptTouchEvent在触摸按下(ACTION_DOWN)阶段,判断触摸点是否在设定的边缘宽度内。如果是,不拦截事件,让ModalNavigationDrawer处理侧滑打开;如果不是,拦截事件交给列表项的SwipeToDismissBox。
  2. SwipeToDismissBox配置:仅开启从右到左的侧滑删除(enableDismissFromEndToStart = true),关闭从左到右的方向,避免和抽屉手势重叠。

这种实现和Gmail的逻辑一致,既保证了边缘侧滑打开抽屉的流畅性,也不影响列表项的侧滑删除功能。

内容的提问来源于stack exchange,提问作者Callum Marks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:38:10