Синхронизировать смену страницы PageView и Slider во флаттере

В моем приложении есть 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 ответа

Собственно проблема в этом случае заключается в том, что при каждом изменении страницы 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 мс, прежде чем обновлять его значение), но, тем не менее, это улучшение. Если у кого-то есть лучшее решение, я рад это слышать.

Пожалуйста, используйте 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()),
Другие вопросы по тегам