Flutter中Overlay/Dialog内水平滚动失效问题求助
在Overlay/Dialog中实现可选择水平滚动列表项的问题解决
问题说明
尝试在Overlay或Dialog内实现可选择的水平滚动列表项,已通过ListView在Overlay中展示内容,但水平滚动功能无效,同时出现如下报错:
The following assertion was thrown during a scheduler callback: A ScrollController is required when Scrollbar.thumbVisibility is true. The Scrollbar was not provided a ScrollController, and attempted to use the PrimaryScrollController, but none was found. 'package:flutter/src/widgets/scrollbar.dart': package:flutter/…/widgets/scrollbar.dart:1 Failed assertion: line 1468 pos 7: 'scrollController != null'
相关代码
插入Overlay的代码
void _insertOverlay(BuildContext context) { late OverlayEntry _overlay; _overlay = OverlayEntry(builder: (ctx) { final size = MediaQuery.of(context).size; print(size.width); return Material( color: Colors.transparent, child: Stack( alignment: Alignment.center, children: [ GestureDetector( onTap: () => _overlay.remove(), child: Container( color: Colors.grey.withAlpha(150), ), ), Positioned.fill( child: Container( width: 500, height: 500, color: Colors.blue, child: Scrollbar( interactive: true, thickness: 20, // thumbVisibility: true, trackVisibility: true, child: ListView.builder( scrollDirection: Axis.horizontal, padding: EdgeInsets.all(2), itemCount: 10, itemBuilder: ((context, index) { return getpriceItem(); })), ), ), ), ], ), ); }); return Overlay.of(context)?.insert(_overlay); }
调用代码
Container( decoration: const BoxDecoration( // shape: BoxShape.circle, color: Colors.red), child: InkWell( onTap: () => _insertOverlay(context), child: const Center(child: Text('1'))), //height: 75.0, //width: 75.0, )
解决步骤
1. 修复Scrollbar报错
报错原因是开启trackVisibility时,Scrollbar必须绑定ScrollController,而Overlay环境下没有默认的PrimaryScrollController。
修改代码,创建并绑定ScrollController:
void _insertOverlay(BuildContext context) { late OverlayEntry _overlay; final scrollController = ScrollController(); _overlay = OverlayEntry(builder: (ctx) { final size = MediaQuery.of(context).size; print(size.width); return Material( color: Colors.transparent, child: Stack( alignment: Alignment.center, children: [ GestureDetector( onTap: () { scrollController.dispose(); _overlay.remove(); }, child: Container( color: Colors.grey.withAlpha(150), ), ), Positioned.fill( child: Container( width: 500, height: 500, color: Colors.blue, child: Scrollbar( controller: scrollController, interactive: true, thickness: 20, trackVisibility: true, child: ListView.builder( controller: scrollController, scrollDirection: Axis.horizontal, padding: EdgeInsets.all(2), itemCount: 10, itemBuilder: ((context, index) { return getpriceItem(); })), ), ), ), ], ), ); }); return Overlay.of(context)?.insert(_overlay); }
2. 解决水平滚动无效问题
水平滚动无效通常是因为ListView子项没有固定宽度,导致无法计算滚动范围。需要给getpriceItem()返回的Widget设置明确宽度:
Widget getpriceItem() { return Container( width: 120, height: 480, margin: EdgeInsets.symmetric(horizontal: 4), color: Colors.white, child: Center(child: Text('选项')), ); }
另外,Positioned.fill会让容器占满屏幕,和手动设置的width:500可能产生约束冲突,建议改用Center包裹容器:
// 替换原Positioned.fill部分 Center( child: Container( width: 500, height: 500, color: Colors.blue, child: Scrollbar(...), ), )
内容的提问来源于stack exchange,提问作者harvinder rathor
相关产品推荐
相关产品推荐

