Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scroll 同步滚动多个可滚动小部件_Scroll_Dart_Controller_Flutter_Synchronization - Fatal编程技术网

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);
  }
),