Синхронизация прокрутки для нескольких прокручиваемых виджетов

#recursion #dart #flutter

#рекурсия #dart #флаттер

Вопрос:

Синхронизация прокрутки для нескольких прокручиваемых виджетов:

Я хочу прокрутить второй список, если прокрутить первый список, и прокрутить первый список, если прокрутить второй список.Это будет рекурсивно, кто-нибудь может помочь в этом, заранее спасибо.

 import 'package:flutter/cupertino.dart';
class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ScrollController firstScroll = ScrollController();
  ScrollController secondScrollController = ScrollController();

  @override
  void initState() {
     super.initState();
     firstScroll.addListener(() {
    //THIS IS called when scroll is triggered,
        secondScrollController
           .jumpTo(firstScroll.offset); // THIS will sync the scroll;
     });

 secondScrollController.addListener(() {
    //THIS IS called when scroll is triggered,
        firstScroll
           .jumpTo(secondScrollController.offset); // THIS will sync the scroll;
     });
   }

   @override
   Widget build(BuildContext context) {
     return Container(
        child: Column(
          children: <Widget>[
            SingleChildScrollView(
             // this is the first scroll
                scrollDirection: Axis.horizontal,
                controller: firstScroll, // THIS IS THE FIRST SCROLL CONTROLLER
                child: Container(
                   //TODO: add your content here here
                ),
            ),
            SingleChildScrollView(
               scrollDirection: Axis.horizontal,
               controller: secondScrollController,
               // HERE YOU SET THE SECOND CONTROLLER
               child: Container(
                  //TODO: add your content here
               ),
             )
        ],
    ),
 );
}
}
 

Ответ №1:

Это потому, что каждый раз, когда вы вызываете jumpTo метод, он вызывает первый, а первый вызывает второй, и у вас будет бесконечный цикл.

Решение заключается в том, что вы создаете свой собственный ScrollController, которому принадлежит метод перехода на другую позицию без уведомления.

Это пользовательский контроллер прокрутки, который вы можете создать:

             class CustomScrollController extends ScrollController {
              CustomScrollController({
                double initialScrollOffset = 0.0,
                keepScrollOffset = true,
                debugLabel,
              }) : super(
                        initialScrollOffset: initialScrollOffset,
                        keepScrollOffset: keepScrollOffset,
                        debugLabel: debugLabel);

              @override
              _UnboundedScrollPosition createScrollPosition(
                ScrollPhysics physics,
                ScrollContext context,
                ScrollPosition oldPosition,
              ) {
                return _UnboundedScrollPosition(
                  physics: physics,
                  context: context,
                  oldPosition: oldPosition,
                  initialPixels: initialScrollOffset,
                );
              }

              void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
                assert(positions.isNotEmpty, 'ScrollController not attached.');
                for (_UnboundedScrollPosition position
                    in new List<ScrollPosition>.from(positions))
                  position.jumpToWithoutGoingIdleAndKeepingBallistic(value);
              }
            }

            class _UnboundedScrollPosition extends ScrollPositionWithSingleContext {
              _UnboundedScrollPosition({
                ScrollPhysics physics,
                ScrollContext context,
                ScrollPosition oldPosition,
                double initialPixels,
              }) : super(
                      physics: physics,
                      context: context,
                      oldPosition: oldPosition,
                      initialPixels: initialPixels,
                    );

              /// There is a feedback-loop between aboveController and belowController. When one of them is
              /// being used, it controls the other. However if they get out of sync, for timing reasons,
              /// the controlled one with try to control the other, and the jump will stop the real controller.
              /// For this reason, we can't let one stop the other (idle and ballistics) in this situation.
              void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
                if (pixels != value) {
                  forcePixels(value);
                }
              }
            }
 

И просто позвоните , чтобы jumpToWithoutGoingIdleAndKeepingBallistic вместо jumpTo .

Рабочий образец здесь:

https://gist.github.com/diegoveloper/75e55ca2e4cee03bff41a26254d6fcf6

Результат

введите описание изображения здесь

Комментарии:

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

2. shrinkWrap: верно, удалите эффект подпрыгивания вашего списка, если вы удалите это значение, у вас могут возникнуть некоторые проблемы в вашем макете, попробуйте использовать Slivers

3. Это единственный дочерний контроллер прокрутки, и мы хотим, чтобы эффект подпрыгивания соответствовал требованиям

4. извините, я обновил свой код: проверьте еще раз -> gist.github.com/diegoveloper/75e55ca2e4cee03bff41a26254d6fcf6

5. Не работает чувак. эффект отскока не появляется, и прокрутка не бесплатна. это рывок.