Flutter Web中SelectionArea嵌套PageView异常:是Bug还是可规避?
场景1:SelectionArea作为PageView父组件
当SelectionArea包裹PageView时,即便给PageView设置了physics: const NeverScrollableScrollPhysics(),选中文本后拖动仍能触发PageView的横向滑动,同时会随机抛出非100%复现的断言错误:
globalRect.size.height >= _dragTargetRelatedToScrollOrigin.size.height
"Drag target size is larger than scrollable size, which may cause bouncing"
复现代码
void main() { runApp( const MyApp(), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: SelectionArea(child: PageViewBug()), ); } } class PageViewBug extends StatefulWidget { const PageViewBug({super.key}); @override State<PageViewBug> createState() => _PageViewBugState(); } class _PageViewBugState extends State<PageViewBug> { final PageController controllerH = PageController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('PageViewBug')), body: PageView( controller: controllerH, physics: const NeverScrollableScrollPhysics(), scrollDirection: Axis.horizontal, children: const [ Center(child: Text("Page1")), Center(child: Text("Page2")), Center(child: Text("Page3")), ], ), ); } }
场景2:SelectionArea下移至PageView子页面层级
调整Widget树结构,将SelectionArea放在PageView的每个子页面组件上方,结构如下:
-MaterialApp --Scaffold ---BlocBuilder ----PageView -----SelectionArea(Screen1) -----SelectionArea(Screen2)
此时拖动选中文本移出屏幕时,会频繁抛出相同的断言异常:
Error: Assertion failed: file:///D:/..../flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart:237:7
globalRect.size.width >= _dragTargetRelatedToScrollOrigin.size.width &&
globalRect.size.height >= _dragTargetRelatedToScrollOrigin.size.height
"Drag target size is larger than scrollable size, which may cause bouncing"
问题分析
这大概率是Flutter框架的内部Bug:SelectionArea的文本选择拖动手势逻辑与PageView这类Scrollable组件的手势处理存在冲突,框架内部的断言校验(用于防止滚动区域异常)在文本拖动超出组件尺寸时被触发,而NeverScrollableScrollPhysics无法完全拦截文本选择带来的滚动触发。
临时解决方案
- 调整Widget层级:尽量将
SelectionArea仅包裹需要文本选择的局部容器,避免直接嵌套PageView这类可滚动组件 - 手势拦截:给
PageView添加GestureDetector,拦截横向拖动手势,避免文本选择拖动触发页面滚动 - 跟进官方修复:可以在Flutter官方Issue仓库搜索相关问题,提交复现案例,等待框架层面的修复
内容的提问来源于stack exchange,提问作者Fabian M

