Прокрутка нескольких прокручиваемых виджетов в синхронизации - PullRequest
0 голосов
/ 25 февраля 2019

Проще говоря:

есть ли способ синхронизировать несколько прокручиваемых виджетов (скажем, SingleSchildScrollView) вместе?


iпросто хочу 2 прокрутки, которые могут прокручивать другую, когда я прокручиваю одну.

таким образом, я могу использовать Stack, чтобы поместить их друг на друга, а другая сзади может прокручивать следующую за передней.

или, может быть, поместите их в другой набор Column или Row, чтобы они были отдельными, но все еще прокручивались, просто прокручивая одну из них.

Я пытался использовать controller, но это не кажетсячтобы делать то, что я думаю.


Попробуйте код, приведенный ниже, например, «ВПРАВО» будет перед «ВЛЕВОМ», и если я попытаюсь прокрутить их, только ВПРАВО будетпереехать.Итак, как мне переместить их вместе в одно и то же время ??

Пожалуйста, не говорите мне, чтобы поместить стек внутрь ListView, это не то, что мне нужно.

class _MyHomePageState extends State<MyHomePage> {

  final ScrollController _mycontroller = new ScrollController();

  @override
  Widget build(BuildContext context) {
    body:
      Container(
        height: 100,
        child:
          Stack( children: <Widget>[
            SingleChildScrollView(
              controller: _mycontroller,
              child: Column( children: <Widget>[
                Text('LEFT            '),
                Text('LEFT            '),
                Text('LEFT            '),
                Text('LEFT            '),
                Text('LEFT            '),
                Text('LEFT            '),
              ],)
            ),
            SingleChildScrollView(
              controller: _mycontroller,
              child: Column(children: <Widget>[
                Text('          RIGHT'),
                Text('          RIGHT'),
                Text('          RIGHT'),
                Text('          RIGHT'),
                Text('          RIGHT'),
                Text('          RIGHT'),
              ],)
            ),
          ])
      )
}}

Я полагаю, что этот вопрос уже задавался ранее на нескольких форумах, но никто не придумал никакого решения или решения.(см. здесь )

Ответы [ 2 ]

0 голосов
/ 30 июня 2019

Спасибо за ваш ответ @Chris, я столкнулся с той же проблемой и построил свое решение поверх вашего.Он работает над несколькими виджетами и позволяет синхронизировать прокрутку из любого виджета в «группе».


PSA: Кажется, это работает нормально, но я только начинаю, и этоможет сломаться самым невероятным образом, который вы могли себе представить


Он работает, используя NotificationListener<ScrollNotification> плюс независимый 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;
      }
    }
  }
}

Идея состоит в том, что вы регистрируете каждый виджет ScrollController с этим помощником, чтобы он имел ссылку на каждый виджет, который нужно прокрутить.Вы можете сделать это, передав массив ScrollController s в конструктор SyncScrollController s или позже, вызвав registerScrollController и передав ScrollController в качестве параметра функции.
Вам потребуетсяпривязать метод processNotification к обработчику событий NotificationListener.Возможно, все это может быть реализовано в самом виджете, но я еще не достаточно опытен для этого.

Использование класса выглядит примерно так:

Создание полей для scollControllers

  ScrollController _firstScroller = new ScrollController();
  ScrollController _secondScroller = new ScrollController();
  ScrollController _thirdScroller = new ScrollController();

  SyncScrollController _syncScroller;

Инициализация SyncScrollController

@override
void initState() {
  _syncScroller = new SyncScrollController([_firstScroller , _secondScroller, _thirdScroller]);
  super.initState();
}

Пример полного NotificationListener

NotificationListener<ScrollNotification>(
  child: SingleChildScrollView(
    controller: _firstScroller,
    child: Container(
    ),
  ),
  onNotification: (ScrollNotification scrollInfo) {
    _syncScroller.processNotification(scrollInfo, _firstScroller);
  }
),

Явно реализуйте приведенный выше пример для каждого прокручиваемого виджета и отредактируйте SyncController (параметр контроллер: ) и processNotification параметр scrollController (выше _firstScroller ) соответственно.Вы могли бы реализовать еще несколько сейфов, таких как проверка _syncScroller != null и т. Д., Выше применяется PSA:)

0 голосов
/ 26 февраля 2019

Мне удалось синхронизировать несколько прокруток, используя их offset, используя их ScrollNotification.

Вот пример грубого кода:

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

в основном каждый SingleChildScrollView имеет свойсобственный controller.каждый controller имеет свои offset значения.используйте NotificationListener<ScrollNotification> для уведомления о любом движении, в любое время, когда они прокручиваются.

затем для каждого жеста прокрутки (я полагаю, что это кадр за кадром), мы можем добавить команду jumpTo(), чтобы установить offset s в любом случае нам нравится.

ура !!

PS.если список имеет другую длину, то смещение будет другим, и вы получите ошибку переполнения стека, если попытаетесь прокрутить его предел.не забудьте добавить некоторые исключения или обработку ошибок.(т.е. if else и т. д.)

...