Scroll 同步滚动多个可滚动小部件
简言之: 有没有办法让多个可滚动小部件(例如,Scroll 同步滚动多个可滚动小部件,scroll,dart,controller,flutter,synchronization,Scroll,Dart,Controller,Flutter,Synchronization,简言之: 有没有办法让多个可滚动小部件(例如,SingleSchildScrollView)同步在一起? 我只需要2个滚动条,可以滚动其他我滚动一个 这样,我可以使用堆栈将它们放在彼此的顶部,后面的一个可以跟随前面的一个滚动 或者可以将它们放在另一组列或行中,这样它们是分开的,但只需滚动其中一个即可滚动 我试着使用控制器,但它似乎没有达到我想象的效果 例如,尝试下面的代码, “RIGHT”将位于“LEFT”的前面,如果我尝试滚动它们,只有RIGHT会移动。那么我如何同时移动它们呢 请不要告诉
SingleSchildScrollView
)同步在一起?
我只需要2个滚动条,可以滚动其他我滚动一个 这样,我可以使用
堆栈
将它们放在彼此的顶部,后面的一个可以跟随前面的一个滚动
或者可以将它们放在另一组列
或行
中,这样它们是分开的,但只需滚动其中一个即可滚动
我试着使用控制器
,但它似乎没有达到我想象的效果
例如,尝试下面的代码, “RIGHT”将位于“LEFT”的前面,如果我尝试滚动它们,只有RIGHT会移动。那么我如何同时移动它们呢 请不要告诉我将堆栈放在
列表视图中,这不是我需要的
class\u MyHomePageState扩展状态{
最终ScrollController_mycontroller=新ScrollController();
@凌驾
小部件构建(构建上下文){
正文:
容器(
身高:100,
儿童:
堆栈(子对象:[
SingleChildScrollView(
控制器:_mycontroller,
子项:列(子项:[
文本('左'),
文本('左'),
文本('左'),
文本('左'),
文本('左'),
文本('左'),
],)
),
SingleChildScrollView(
控制器:_mycontroller,
子项:列(子项:[
文本('右'),
文本('右'),
文本('右'),
文本('右'),
文本('右'),
文本('右'),
],)
),
])
)
}}
我相信这个问题以前曾在多个论坛上被问过,但没有人对此做出结论或提出解决方案。(请参阅)我通过使用多个滚动条的偏移量,利用它们的滚动通知来同步多个滚动条
下面是一个粗略的代码示例:
class _MyHomePageState extends State<MyHomePage> {
ScrollController _mycontroller1 = new ScrollController(); // make seperate controllers
ScrollController _mycontroller2 = new ScrollController(); // for each scrollables
@override
Widget build(BuildContext context) {
body:
Container(
height: 100,
child: NotificationListener<ScrollNotification>( // this part right here is the key
Stack( children: <Widget>[
SingleChildScrollView( // this one stays at the back
controller: _mycontroller1,
child: Column( children: <Widget>[
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
],)
),
SingleChildScrollView( // this is the one you scroll
controller: _mycontroller2,
child: Column(children: <Widget>[
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
],)
),
]),
onNotification: (ScrollNotification scrollInfo) { // HEY!! LISTEN!!
// this will set controller1's offset the same as controller2's
_mycontroller1.jumpTo(_mycontroller2.offset);
// you can check both offsets in terminal
print('check -- offset Left: '+_mycontroller1.offset.toInt().toString()+ ' -- offset Right: '+_mycontroller2.offset.toInt().toString());
}
)
)
}}
class\u MyHomePageState扩展状态{
ScrollController _mycontroller1=新建ScrollController();//创建单独的控制器
ScrollController _mycontroller2=新的ScrollController();//对于每个滚动条
@凌驾
小部件构建(构建上下文){
正文:
容器(
身高:100,
child:NotificationListener(//这里的这部分是键
堆栈(子对象:[
SingleChildScrollView(//这个在后面
控制器:_mycontroller1,
子项:列(子项:[
文本('左'),
文本('左'),
文本('左'),
文本('左'),
文本('左'),
文本('左'),
],)
),
SingleChildScrollView(//这是您滚动的一个
控制器:_mycontroller2,
子项:列(子项:[
文本('右'),
文本('右'),
文本('右'),
文本('右'),
文本('右'),
文本('右'),
],)
),
]),
onNotification:(滚动通知滚动信息){//嘿!!听着!!
//这将使控制器1的偏移量与控制器2的偏移量相同
_mycontroller1.跳转到(_mycontroller2.偏移);
//可以在端子中检查两个偏移
打印('check--offset Left:'+_mycontroller1.offset.toInt().toString()+'--offset Right:'+_mycontroller2.offset.toInt().toString());
}
)
)
}}
基本上,每个SingleChildScrollView
都有自己的控制器。
每个控制器
都有自己的偏移量
值。
使用NotificationListener
随时通知任何移动
然后对于每个滚动手势(我相信这是一帧一帧的基础),
我们可以添加jumpTo()
命令以任意方式设置offset
s
干杯
另外,如果列表的长度不同,那么偏移量将不同,如果您试图滚动超过其限制,则会出现堆栈溢出错误。确保添加一些异常或错误处理。(例如,if else
等)谢谢你的回答@Chris,我遇到了同样的问题,并在你的基础上构建了我的解决方案。它可以在多个小部件上工作,并允许从“组”中的任何小部件进行同步滚动
PSA:这似乎很好,但我才刚刚开始,这可能会以你能想象到的最美妙的方式打破
它使用一个NotificationListener
加上一个独立的ScrollController
为每个应该同步的可滚动小部件工作。
该类如下所示:
class SyncScrollController {
List<ScrollController> _registeredScrollControllers = new List<ScrollController>();
ScrollController _scrollingController;
bool _scrollingActive = false;
SyncScrollController(List<ScrollController> controllers) {
controllers.forEach((controller) => registerScrollController(controller));
}
void registerScrollController(ScrollController controller) {
_registeredScrollControllers.add(controller);
}
void processNotification(ScrollNotification notification, ScrollController sender) {
if (notification is ScrollStartNotification && !_scrollingActive) {
_scrollingController = sender;
_scrollingActive = true;
return;
}
if (identical(sender, _scrollingController) && _scrollingActive) {
if (notification is ScrollEndNotification) {
_scrollingController = null;
_scrollingActive = false;
return;
}
if (notification is ScrollUpdateNotification) {
_registeredScrollControllers.forEach((controller) => {if (!identical(_scrollingController, controller)) controller..jumpTo(_scrollingController.offset)});
return;
}
}
}
}
初始化SyncScrollController
完整NotificationListener示例
NotificationListener(
子:SingleChildScrollView(
控制器:_firstScroller,
子:容器(
),
),
onNotification:(滚动通知滚动信息){
_processNotification(scrollInfo,_firstScroller);
}
),
为每个可滚动小部件实现上述示例,并相应地编辑SyncController
(参数controller:)和processNotification
scrollController参数(在第一个Scroller上方)。您可以实现更多的故障保护,如
class SyncScrollController {
List<ScrollController> _registeredScrollControllers = new List<ScrollController>();
ScrollController _scrollingController;
bool _scrollingActive = false;
SyncScrollController(List<ScrollController> controllers) {
controllers.forEach((controller) => registerScrollController(controller));
}
void registerScrollController(ScrollController controller) {
_registeredScrollControllers.add(controller);
}
void processNotification(ScrollNotification notification, ScrollController sender) {
if (notification is ScrollStartNotification && !_scrollingActive) {
_scrollingController = sender;
_scrollingActive = true;
return;
}
if (identical(sender, _scrollingController) && _scrollingActive) {
if (notification is ScrollEndNotification) {
_scrollingController = null;
_scrollingActive = false;
return;
}
if (notification is ScrollUpdateNotification) {
_registeredScrollControllers.forEach((controller) => {if (!identical(_scrollingController, controller)) controller..jumpTo(_scrollingController.offset)});
return;
}
}
}
}
ScrollController _firstScroller = new ScrollController();
ScrollController _secondScroller = new ScrollController();
ScrollController _thirdScroller = new ScrollController();
SyncScrollController _syncScroller;
@override
void initState() {
_syncScroller = new SyncScrollController([_firstScroller , _secondScroller, _thirdScroller]);
super.initState();
}
NotificationListener<ScrollNotification>(
child: SingleChildScrollView(
controller: _firstScroller,
child: Container(
),
),
onNotification: (ScrollNotification scrollInfo) {
_syncScroller.processNotification(scrollInfo, _firstScroller);
}
),