使用两个ReorderableRow报错:ScrollController绑定多个滚动视图
问题:多ReorderableRow共存时拖拽异常
在Flutter项目中引入reorderables: ^0.5.0包实现两个可拖拽排序的ReorderableRow组件时,出现以下问题:
- 移除第二个
ReorderableRow后,第一个组件的排序功能正常 - 同时使用两个组件时,拖拽第一个
ReorderableRow内的元素会消失,并抛出断言异常:ScrollController attached to multiple scroll views
复现代码
import 'package:flutter/material.dart'; import 'package:reorderables/reorderables.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Drag and Drop Lists', theme: ThemeData( primarySwatch: Colors.blue, ), home: OrderableRow(), ); } } class OrderableRow extends StatefulWidget { const OrderableRow({Key? key}) : super(key: key); @override State<OrderableRow> createState() => _OrderableRowState(); } class _OrderableRowState extends State<OrderableRow> { late List<Widget> _listOfWidgets; late List<Widget> _listOfWidgets2; @override void initState() { super.initState(); _listOfWidgets = <Widget>[ Container(color: Colors.blue, key: const ValueKey(1), child: const Text('blue')), Container(color: Colors.red, key: const ValueKey(2), child: const Text('red')), Container(color: Colors.green, key: const ValueKey(3), child: const Text('green')), ]; _listOfWidgets2 = <Widget>[ Container(color: Colors.blue, key: const ValueKey(-1), child: const Text('blue')), Container(color: Colors.red, key: const ValueKey(-2), child: const Text('red')), Container(color: Colors.green, key: const ValueKey(-3), child: const Text('green')), ]; } @override Widget build(BuildContext context) { void _onReorder(int oldIndex, int newIndex){ setState(() { Widget col = _listOfWidgets.removeAt(oldIndex); _listOfWidgets.insert(newIndex,col); }); } void _onReorder2(int oldIndex, int newIndex){ setState(() { Widget col = _listOfWidgets2.removeAt(oldIndex); _listOfWidgets2.insert(newIndex,col); }); } return Column( children: [ ReorderableRow( onReorder: _onReorder, children: _listOfWidgets, ), ReorderableRow( onReorder: _onReorder2, children: _listOfWidgets2, ), ], ); } }
报错堆栈
══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════ The following assertion was thrown while handling a gesture: Assertion failed: file:///name/development/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart:108:12 _positions.length == 1 "ScrollController attached to multiple scroll views." When the exception was thrown, this was the stack: dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49 throw_ dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3 assertFailed packages/flutter/src/widgets/scroll_controller.dart 108:33 get position packages/flutter/src/widgets/scroll_controller.dart 115:33 get offset packages/reorderables/src/widgets/reorderable_flex.dart 381:53 [_scrollTo] packages/reorderables/src/widgets/reorderable_flex.dart 741:11 <fn> packages/flutter/src/widgets/drag_target.dart 746:47 didEnter packages/flutter/src/widgets/drag_target.dart 902:22 <fn> dart-sdk/lib/collection/list.dart 161:15 firstWhere packages/flutter/src/widgets/drag_target.dart 897:56 updateDrag packages/flutter/src/widgets/drag_target.dart 824:5 new packages/flutter/src/widgets/drag_target.dart 554:35 [_startDrag] packages/flutter/src/widgets/drag_target.dart 483:37 <fn> packages/flutter/src/gestures/multidrag.dart 295:53 <fn> packages/flutter/src/gestures/recognizer.dart 198:24 invokeCallback packages/flutter/src/gestures/multidrag.dart 295:14 [_startDrag] packages/flutter/src/gestures/multidrag.dart 285:48 <fn> packages/flutter/src/gestures/multidrag.dart 530:7 [_delayPassed] dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19 internalCallback Handler: "onStart" Recognizer: DelayedMultiDragGestureRecognizer#02801 ════════════════════════════════════════════════════════════════════════════════════════════════════ Another exception was thrown: Assertion failed: file:///name/development/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart:108:12
问题原因
ReorderableRow组件默认会使用同一个全局ScrollController实例,当多个ReorderableRow同时存在时,就会出现一个控制器绑定多个滚动视图的情况,触发Flutter的断言检查,导致拖拽功能异常。
解决方法
为每个ReorderableRow创建独立的ScrollController实例,并通过scrollController参数传入,确保每个组件拥有专属的控制器,避免冲突。同时要记得在组件销毁时释放控制器资源。
修改后的代码
import 'package:flutter/material.dart'; import 'package:reorderables/reorderables.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Drag and Drop Lists', theme: ThemeData( primarySwatch: Colors.blue, ), home: OrderableRow(), ); } } class OrderableRow extends StatefulWidget { const OrderableRow({Key? key}) : super(key: key); @override State<OrderableRow> createState() => _OrderableRowState(); } class _OrderableRowState extends State<OrderableRow> { late List<Widget> _listOfWidgets; late List<Widget> _listOfWidgets2; // 为每个ReorderableRow创建独立的ScrollController late ScrollController _controller1; late ScrollController _controller2; @override void initState() { super.initState(); _controller1 = ScrollController(); _controller2 = ScrollController(); _listOfWidgets = <Widget>[ Container(color: Colors.blue, key: const ValueKey(1), child: const Text('blue')), Container(color: Colors.red, key: const ValueKey(2), child: const Text('red')), Container(color: Colors.green, key: const ValueKey(3), child: const Text('green')), ]; _listOfWidgets2 = <Widget>[ Container(color: Colors.blue, key: const ValueKey(-1), child: const Text('blue')), Container(color: Colors.red, key: const ValueKey(-2), child: const Text('red')), Container(color: Colors.green, key: const ValueKey(-3), child: const Text('green')), ]; } @override void dispose() { // 销毁时释放控制器资源 _controller1.dispose(); _controller2.dispose(); super.dispose(); } @override Widget build(BuildContext context) { void _onReorder(int oldIndex, int newIndex){ setState(() { Widget col = _listOfWidgets.removeAt(oldIndex); _listOfWidgets.insert(newIndex,col); }); } void _onReorder2(int oldIndex, int newIndex){ setState(() { Widget col = _listOfWidgets2.removeAt(oldIndex); _listOfWidgets2.insert(newIndex,col); }); } return Column( children: [ ReorderableRow( scrollController: _controller1, // 传入第一个控制器 onReorder: _onReorder, children: _listOfWidgets, ), ReorderableRow( scrollController: _controller2, // 传入第二个控制器 onReorder: _onReorder2, children: _listOfWidgets2, ), ], ); } }
内容的提问来源于stack exchange,提问作者Ulmer
相关产品推荐
相关产品推荐

