PageController not set properly within the PageView module in Flutter. Positions not empty error popping up

Viewed 1344

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 the PageView index by pressing on a button to switch from screens within the PageView, 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?

2 Answers

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);
      }
    });
//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.

Related