Синхронизировать изменение страницы PageView и Slider в флаттере - PullRequest
0 голосов
/ 04 марта 2020

В моем приложении у меня есть PageView и Slider. Когда я прокручиваю PageView, я ожидаю, что Slider изменит свое значение, и когда я сдвигаю Slider, я ожидаю, что страница PageView также изменится. Для этого у меня есть состояние, которое должно быть value из Slider, и в onChanged у меня будет изменение его значения, а в onChangeEnd оживит PageView до позиции желания:

Slider(
   value: _sliderValue,
   onChanged: (val) {
      setState(() {
         _sliderValue = val;
      });
   },
   onChangeEnd: (val) {
      _controller.animateToPage(val.toInt(),
          duration: Duration(milliseconds: 300), curve: Curves.ease);
      },
   max: (pages.length - 1).toDouble())

И в PageView мне также нужно обновить _sliderValue, чтобы он работал при прокрутке PageView:

PageView.builder(
  onPageChanged: (page) {
    setState(() {
       _sliderValue = page.toDouble();
    });
  },
)

Проблема в том, что у меня теперь есть 2 места, в которых я изменяю _sliderValue - одно в onChanged для Slider, чтобы быть отзывчивым, одно в onPageChanged для работы с прокруткой. Это заставляет слайдер сотрясаться, когда я нажимаю на него несколько раз.

Есть ли способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 05 марта 2020

На самом деле проблема в этом случае заключается в том, что при каждом изменении страницы срабатывает обратный вызов onPageChanged для PageView. Например, если мы находимся на странице 1 и используем Slider для перехода на страницу 5, то onPageChanged будет вызываться 4 раза (для страницы 2-3-4-5) и, как результат, состояние значения Slider будет изменяться повторно 4 раза. Это заставляет стук Slider прыгать повсюду.

Я попытался исправить это, имея Timer внутри onPageChanged, чтобы подождать некоторое время, прежде чем вызвать setState, поэтому он срабатывает только после завершения последнего изменения страницы.

// Define a Timer object in your state
Timer _timer;
PageView.builder(
  onPageChanged: (page) {
    // If there is a Timer running, cancel it
    if (_timer != null) {
      _timer.cancel();
    }
    // Setup a new Timer
    _timer = Timer(Duration(milliseconds: 300), () {
      setState(() {
        _sliderValue = page.toDouble();
      });
    });
  },
)

Это может показаться хакерским, а результат на самом деле не идеален (когда вы прокручиваете страницу вручную, Slider будет придется подождать 300 мс, прежде чем обновлять его значение), но, тем не менее, это улучшение. Если у кого-то есть лучшее решение, я буду рад его услышать.

0 голосов
/ 04 марта 2020

Пожалуйста, используйте val.round () вместо val.toInt ().

            Slider(
            value: _sliderValue,
            onChanged: (val) {
              setState(() {
                _sliderValue = val.round().toDouble(); // this line changed.
              });
            },
            onChangeEnd: (val) {
              _controller.animateToPage(val.round(), // this line changed.
                  duration: Duration(milliseconds: 300), curve: Curves.ease);
            },
            max: (pages.length - 1).toDouble()),
...