Chr*_*ris 7 scroll synchronization controller dart flutter
简而言之:
有没有一种方法可以将多个可滚动的小部件(例如SingleSchildScrollView)同步在一起?
我只想要2个可滚动项,可以在我滚动一个时滚动另一个。
这样,我可以Stack将它们放在彼此的顶部,而后面的一个可以跟随前面的一个滚动。
或将它们放在另一组中Column,Row以便它们是分开的,但仍可以通过滚动其中一个来滚动。
我尝试使用,controller但似乎并没有按照我的想法做。
尝试下面的代码,例如,“ RIGHT”将在“ LEFT”的前面,如果我尝试滚动它们,则只有RIGHT会移动。那么如何同时将它们一起移动?
请不要告诉我将堆栈放在a内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'),
],)
),
])
)
}}
Run Code Online (Sandbox Code Playgroud)
我相信之前在多个论坛中都曾问过这个问题,但没有人对此提出任何结论或解决方案。(请参阅此处)
我刚刚面临同样的问题,现在有一个官方包:linked_scroll_controller。
使用该包,您只需要创建一个 masterLinkedScrollControllerGroup来跟踪滚动偏移,然后它将ScrollController通过LinkedScrollControllerGroup.addAndGet().
我设法通过使用他们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());
}
)
)
}}
Run Code Online (Sandbox Code Playgroud)
基本上每个SingleChildScrollView都有自己的controller。每个人controller都有自己的offset价值观。使用NotificationListener<ScrollNotification>来通知任何移动,无论何时滚动。
然后对于每个滚动手势(我相信这是逐帧的),我们可以添加jumpTo()命令以offset我们喜欢的任何方式设置s。
干杯!!
附注。如果列表的长度不同,则偏移量将不同,如果您尝试滚动超过其限制,则会出现堆栈溢出错误。确保添加一些异常或错误处理。(即if else等)
感谢您的回答@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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个想法是你ScrollController用那个助手注册每个小部件,这样它就会有一个对每个应该滚动的小部件的引用。您可以通过将ScrollControllers数组传递给SyncScrollControllers 构造函数,或稍后通过调用 sregisterScrollController并将其ScrollController作为参数传递给函数来完成此操作。
您需要将该processNotification方法绑定到NotificationListener. 这可能全部在小部件本身中实现,但我对此还没有足够的经验。
使用该类看起来像这样:
为 scollControllers 创建字段
ScrollController _firstScroller = new ScrollController();
ScrollController _secondScroller = new ScrollController();
ScrollController _thirdScroller = new ScrollController();
SyncScrollController _syncScroller;
Run Code Online (Sandbox Code Playgroud)
初始化 SyncScrollController
@override
void initState() {
_syncScroller = new SyncScrollController([_firstScroller , _secondScroller, _thirdScroller]);
super.initState();
}
Run Code Online (Sandbox Code Playgroud)
完整的 NotificationListener 示例
NotificationListener<ScrollNotification>(
child: SingleChildScrollView(
controller: _firstScroller,
child: Container(
),
),
onNotification: (ScrollNotification scrollInfo) {
_syncScroller.processNotification(scrollInfo, _firstScroller);
}
),
Run Code Online (Sandbox Code Playgroud)
显然,为每个可滚动小部件实现上述示例,并相应地编辑SyncController(参数控制器processNotification:)和scrollController 参数(在_firstScroller上方)。您可能会_syncScroller != null在 PSA 之上实施更多故障保险,例如检查等:)
如果您的 UI 很简单,则包装两个滚动小部件 - 比方说两个 Column - 带有相反的小部件 - 例如 Row - 然后使用像这样的 SingleChildScrollView
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Row(
children: [
//first column
Column(),
//second column
Column(),
],
),
)
Run Code Online (Sandbox Code Playgroud)
如果很复杂,你可以使用像这样的滚动控制器
late final ScrollController scrollController1;
late final ScrollController scrollController2;
@override
void initState() {
scrollController1 = ScrollController();
scrollController2 = ScrollController();
scrollController1.addListener(() {
if (scrollController1.offset != scrollController2.offset) {
scrollController2.jumpTo(scrollController1.offset);
}
});
scrollController2.addListener(() {
if (scrollController1.offset != scrollController2.offset) {
scrollController1.jumpTo(scrollController2.offset);
}
});
super.initState();
}
Run Code Online (Sandbox Code Playgroud)
然后将每个滚动控制器添加到您拥有的每个滚动小部件中,如下所示
SingleChildScrollView(
scrollDirection: Axis.vertical,
controller: scrollController1,
child: Column(), // column 1
)
SingleChildScrollView(
scrollDirection: Axis.vertical,
controller: scrollController2,
child: Column(), // column 2
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
855 次 |
| 最近记录: |