简单地说:
是否可以将多个可滚动的小部件(例如SingleSchildScrollView
)同步在一起?
我只想要2个可滚动对象,它们可以在我滚动一个时滚动另一个。
这样,我可以使用Stack
将它们放在彼此的顶部,而后面的一个可以跟随前面的一个滚动。
或者可以将它们放在另一组Column
或Row
中,以便它们是分开的,但仍然可以通过滚动其中一个来滚动。
我尝试使用controller
,但似乎并没有按照我的想法做。
例如,尝试以下代码, “ RIGHT”将在“ LEFT”的前面,如果我尝试滚动它们,则只有RIGHT会移动。那么如何同时将它们一起移动?
请不要告诉我将堆栈放在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'),
],)
),
])
)
}}
我相信之前曾在多个论坛中提出过这个问题,但没有人提出任何结论或解决方案。 (请参阅here)
答案 0 :(得分:6)
我正面临着同样的问题,现在有一个官方软件包:linked_scroll_controller。
使用该软件包,您只需创建一个母版LinkedScrollControllerGroup
来跟踪滚动偏移量,然后它将通过{{3}为您提供单独的div
(保持同步) }。
答案 1 :(得分:1)
我找到了这个并为我工作
static final tracking = TrackingScrollController();
// implementation
child: ListView(
controller: tracking,
还可以处理多个综合浏览量。
答案 2 :(得分:0)
我设法通过使用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
等)
答案 3 :(得分:0)
感谢您的回答@Chris,我遇到了同样的问题,并在您的问题上建立了解决方案。它可以在多个窗口小部件上工作,并可以从“组”中的任何窗口小部件进行同步滚动。
PSA:这似乎很好,但是我才刚刚开始,这可能会以您能想象的最美妙的方式打破
它为每个应同步的可滚动Widget使用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
,以便它具有对应该滚动的每个小部件的引用。您可以通过将ScrollController
的数组传递给SyncScrollController
的构造函数来实现,或者稍后通过调用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示例
NotificationListener<ScrollNotification>(
child: SingleChildScrollView(
controller: _firstScroller,
child: Container(
),
),
onNotification: (ScrollNotification scrollInfo) {
_syncScroller.processNotification(scrollInfo, _firstScroller);
}
),
可能为每个可滚动小部件实现上述示例,并编辑SyncController
(参数 controller:)和processNotification
scrollController参数(在 _firstScroller 上方) )。您可以实施更多的故障保险,例如检查_syncScroller != null
等,以上适用PSA:)