проще говоря:
есть ли способ синхронизировать несколько прокручиваемых виджетов (скажем, SingleSchildScrollView)?
мне просто нужны 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'),
],)
),
])
)
}}
я полагаю, что этот вопрос уже задавался на нескольких форумах, но никто не сделал вывод или решение по этому поводу. (см. здесь)
@pskink, я просто хочу знать, как прокручивать 2 виджета вместе. в конечном итоге я хотел сделать что-то вроде это
@pskink эй, я не могу открыть твою ссылку. можете ли вы вместо этого вставить содержимое, чтобы ответить на этот вопрос?
@pskink привет!! ваш кусок кода помогает мне. это вроде работает, с моими предыдущими фрагментами кода, которые я пробовал. Пока он выглядит хорошо, я попытаюсь добавить это в свой проект и посмотреть, работает ли он так, как ожидалось. СКОРО ОБНОВИТСЯ!!!!
как я уже сказал: вы не должны следовать этому пути: это плохой обходной путь
@pskink, но пока это единственное решение, которое делает то, что я хотел.
вместо этого вы должны изменить свой дизайн пользовательского интерфейса
@pskink хорошо тогда. но все равно спасибо :) это все же помогло мне лучше понять флаттер. привет дружище!!





мне удалось синхронизировать несколько прокручиваемых с помощью их 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 так, как нам нравится.
ваше здоровье!!
PS. если список имеет разную длину, то смещение будет другим, и вы получите ошибку переполнения стека, если попытаетесь прокрутить его предел. не забудьте добавить некоторые исключения или обработку ошибок. (например, if else и т. д.)
@sivakumar посмотри мой ответ, это должно решить твою проблему
Спасибо за ваш ответ @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 с этим помощником, чтобы у него была ссылка на каждый виджет, который нужно прокручивать. Вы можете сделать это, передав массив ScrollControllers конструктору SyncScrollControllers или позже, вызвав 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<ScrollNotification>(
child: SingleChildScrollView(
controller: _firstScroller,
child: Container(
),
),
onNotification: (ScrollNotification scrollInfo) {
_syncScroller.processNotification(scrollInfo, _firstScroller);
}
),
Обязательно реализуйте приведенный выше пример для каждого прокручиваемого виджета и соответствующим образом отредактируйте параметры SyncController (параметр контроллер:) и processNotification scrollController (выше _firstScroller). Вы можете реализовать еще несколько отказоустойчивых средств, таких как проверка _syncScroller != null и т. д., Применяется выше PSA :)
Продолжая двигаться вперед, я понимаю, почему это было бы не так оптимально, производительность явно страдает, если все начинает расти.
Чувак, твое решение с прослушиванием просто потрясающее. Мне нравится, как вы избавились от рекурсивных изменений положения прокрутки и обработали их как отдельный класс Sync.
Мне нужно было установить начальное смещение для контроллеров прокрутки, а linked_scroll_controller, похоже, сейчас это не поддерживает. Этот подход работает в моем случае, так как я могу установить смещение для каждого ScrollController. Спасибо!
Я только что столкнулся с той же проблемой, и теперь для этого есть официальный пакет: linked_scroll_controller.
Используя этот пакет, вам просто нужно создать мастер LinkedScrollControllerGroup, чтобы отслеживать смещение прокрутки, а затем он предоставит вам отдельные ScrollControllers (синхронизированные) через LinkedScrollControllerGroup.addAndGet().
Я протестировал его, и хорошо, если все прокручиваемые виджеты имеют одинаковую высоту. Но мои виджеты имеют разную высоту, и мне нужно что-то, что принимает не фактическое количество пикселей, а процент прокрутки. Если у кого-то есть решение для меня, пожалуйста, дайте мне знать.
Я нашел этот и работал на меня
static final tracking = TrackingScrollController();
// implementation
child: ListView(
controller: tracking,
а также работать с несколькими просмотрами страниц.
Привет @malik kurosaki, не могли бы вы расширить свой ответ, он не работает. Почему вы сделали его статичным?
зачем вам такой странный UX-дизайн? почему бы не использовать один вид прокрутки?