Синхронизировать смену страницы 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()),