PageController not set properly within the PageView module in Flutter. Positions not empty error popping up
1,177
Solution 1
The proper way to fix this issue for me was to wrap this part:
ShareBloc.getInstance().pageViewIndexStream.listen((index) {
_controller.animateToPage(index,
duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
});
With:
ShareBloc.getInstance().pageViewIndexStream.listen((index) {
if (_controller.hasClients) { // <-- this is the fix!
_controller.animateToPage(index,
duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
}
});
Solution 2
//This will run just once
@override
void initState() {
super.initState();
//This code is the same as your _onLoad method, you don't neet to run it on the build method anymore
_controller = PageController();
ShareBloc.getInstance().pageViewIndexStream.listen((index) {
_controller.animateToPage(index,
duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
});
}
just like the dispose method, the StatefulWidget has an initState method which runs once and only once (when it's inserted into the tree). After that when the build method runs again this code will not run.
Author by
Logan
Updated on December 21, 2022Comments
-
Logan over 1 year
I started programming using the Flutter framework and immediately noticed an odd issue popping up (see below for more info).
The problem occurs when: After returning to the
MainScreen
and trying to change from thePageView
index by pressing on a button to switch from screens within thePageView
, I get this error:[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 110 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
This is my MainScreen:
class MainScreen extends StatefulWidget { @override State<StatefulWidget> createState() => MainScreenState(); } class MainScreenState extends State<MainScreen> { PageController _controller; void _onLoad() { _controller = PageController(); ShareBloc.getInstance().pageViewIndexStream.listen((index) { _controller.animateToPage(index, duration: Duration(milliseconds: 200), curve: Curves.easeInOut); }); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { _onLoad(); return PageView( controller: _controller, physics: NeverScrollableScrollPhysics(), children: [ FirstScreen(), SecondScreen(), ], ); } }
This is my
RxDart
Sharable
file:import 'package:rxdart/rxdart.dart'; class ShareBloc { static ShareBloc _instance; BehaviorSubject<dynamic> _subjectCounter; static ShareBloc getInstance() { if (_instance == null) _instance = ShareBloc(); return _instance; } ShareBloc() { _subjectCounter = new BehaviorSubject<dynamic>(); } Stream<dynamic> get getStream => pageViewIndexStream.stream; void onShare(dynamic data) { _subjectCounter.sink.add(data); } void dispose() { if (_subjectCounter != null) { _subjectCounter.close(); _instance = null; } } }
Can someone tell me what I am doing wrong here?
-
EdwynZN almost 4 yearsThe build method can rebuild several times (like when popping up and returning to the page). When that happens the _onLoad() runs again creating another page controller and creating a new listener without disposing the old one first, try moving the _onLoad to the initState and check if the error disappear
-
Logan almost 4 yearsYes, I also tried that approach as well. It seems that the previous controller is still in the PageView module. So, how can I replace it without getting the error popping up every single time when I enter my page?
-
-
Logan almost 4 yearsI already found the fix for it! You need to check if the controller has clients before continuing. And I did put it in the initState method.
-
EdwynZN almost 4 yearsyeah if you run the code several times you need to check if there are any clients before adding another listener, in init state that can be redundant because you're creating the controller there and never adding a listener again. Also one question, where do you create pageViewIndexStream.stream? I see you used it in both the widget and the bloc but I never see where does that comes from
-
Logan almost 4 yearsIt is in the bloc file: Stream<dynamic> get getStream => pageViewIndexStream.stream;