Flutter ListView单Slidable展开实现及点击关闭报错修复
问题根因
Slidable.of(context) 空指针、无法触发关闭的核心原因是传入的context不包含Slidable的上下文信息:Slidable.of方法的逻辑是沿当前context的父级链向上查找Slidable注册的InheritedWidget实例,如果你直接使用Slidable外层build方法提供的context,这个context属于Slidable的父级节点,向上查找永远触达不到Slidable自身的注册节点,自然返回null。
另外要实现列表内单Slidable展开的互斥效果,不需要手动维护展开状态,库本身已经提供了内置支持。
修复步骤
1. 解决点击InkWell无法关闭Slidable的问题
两种经过验证的实现方案,选其一即可:
- 方案一(最简便):在Slidable的child层嵌套
Builder组件,使用Builder提供的子节点上下文查找Slidable实例。这个context是Slidable挂载完成后生成的子节点上下文,能正确向上查找到Slidable实例。
代码示例:Slidable( // 自行补充actionPane等配置 child: Builder( builder: (innerContext) { return InkWell( onTap: () { // 调用close关闭当前面板 Slidable.of(innerContext)?.close(); // 此处写你原本InkWell的点击业务逻辑 }, child: const TCard(), // 你的自定义卡片组件 ); }, ), ) - 方案二(无context依赖):给每个Slidable绑定唯一
GlobalKey,点击时直接通过key获取SlidableState调用close方法,完全规避context查找的问题,适合列表项结构复杂的场景。
2. 实现同列表单Slidable互斥展开
直接给ListView下所有Slidable配置相同的groupTag参数即可,flutter_slidable 2.x以上版本内置了同组Slidable的互斥逻辑:当展开新的Slidable时,组内其他已展开的Slidable会自动关闭,不需要手写状态监听、遍历关闭的逻辑。
代码示例:
ListView.builder( itemCount: yourList.length, itemBuilder: (context, index) { return Slidable( // 所有列表项配置同一个groupTag即可开启互斥 groupTag: 'single_expand_list', endActionPane: ActionPane( motion: const ScrollMotion(), children: [ // 你的滑动操作按钮,比如删除、编辑 ], ), // 此处放前面写的包了Builder的InkWell+TCard child: Builder(/* 前面的InkWell逻辑 */), ); }, )
避坑提示
- 不要在Slidable的父级context中调用
Slidable.of,必然拿不到实例 - 如果需要在列表外部触发关闭所有已展开的Slidable,给对应SlidableGroup配置全局key后调用
SlidableGroup.of(context).closeAll()即可 - 不要手动维护列表项的展开/关闭状态做互斥,官方groupTag能力已经处理了滑动冲突、动画时序的问题,手写逻辑容易出现状态不同步的问题
内容的提问来源于stack exchange,提问作者madol
相关产品推荐
相关产品推荐

