Search code examples
flutterexceptionscrollview

Unhandled Exception ScrollController not attached to any scroll views


I always get this error and don't understand why it is happening. The App starts perfectly fine but when I try to login it stucks and throws this error. Can someone tell me what Im doing wrong.

E/flutter ( 3070): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 110 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
[38;5;244mE/flutter ( 3070): #0      _AssertionError._doThrowNew  (dart:core-patch/errors_patch.dart:42:39)[39;49m
[38;5;244mE/flutter ( 3070): #1      _AssertionError._throwNew  (dart:core-patch/errors_patch.dart:38:5)[39;49m
[38;5;244mE/flutter ( 3070): #2      ScrollController.position[39;49m
[38;5;244mE/flutter ( 3070): #3      PageController.animateToPage[39;49m
[38;5;248mE/flutter ( 3070): #4      _PreviewMobilePortraitState.initState.<anonymous closure>[39;49m
[38;5;244mE/flutter ( 3070): #5      _rootRunUnary  (dart:async/zone.dart:1134:38)[39;49m
[38;5;244mE/flutter ( 3070): #6      _CustomZone.runUnary  (dart:async/zone.dart:1031:19)[39;49m
[38;5;244mE/flutter ( 3070): #7      _CustomZone.runUnaryGuarded  (dart:async/zone.dart:933:7)[39;49m
[38;5;244mE/flutter ( 3070): #8      _CustomZone.bindUnaryCallbackGuarded.<anonymous closure>  (dart:async/zone.dart:970:26)[39;49m
[38;5;244mE/flutter ( 3070): #9      _rootRunUnary  (dart:async/zone.dart:1138:13)[39;49m
[38;5;244mE/flutter ( 3070): #10     _CustomZone.runUnary  (dart:async/zone.dart:1031:19)[39;49m
[38;5;244mE/flutter ( 3070): #11     _CustomZone.bindUnaryCallback.<anonymous closure>  (dart:async/zone.dart:954:26)[39;49m
[38;5;244mE/flutter ( 3070): #12     _Timer._runTimers  (dart:isolate-patch/timer_impl.dart:384:19)[39;49m
[38;5;244mE/flutter ( 3070): #13     _Timer._handleMessage  (dart:isolate-patch/timer_impl.dart:418:5)[39;49m
[38;5;244mE/flutter ( 3070): #14     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:174:12)[39;49m

My code in the PreviewMobilePortraitState looks like this:

@override
  void initState() {
    super.initState();
    //cycle through pages
    Timer.periodic(Duration(seconds: 4), (Timer timer) {
      if (_currentPage < 3) {
        _currentPage++;
      } else {
        _currentPage = 0;
      }

      _pageController.animateToPage(
        _currentPage,
        duration: Duration(milliseconds: 400),
        curve: Curves.easeInCubic,
      );
    });
  }

Solution

  • PageView is not ready when you call _pageController.animateToPage
    You can use addPostFrameCallback and check _pageController.hasClients

    code snippet

    @override
    void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          Timer.periodic(Duration(seconds: 4), (Timer timer) {
            if (_currentPage < 3) {
              _currentPage++;
            } else {
              _currentPage = 0;
            }
    
            if(_pageController.hasClients) {
              _pageController.animateToPage(
                _currentPage,
                duration: Duration(milliseconds: 400),
                curve: Curves.easeInCubic,
              );
            }
    
          });
        });
    }
    

    working demo to simulate this case

    enter image description here

    full test code

    import 'package:flutter/material.dart';
    import 'dart:async';
    
    class Feature {
      String name;
      Color color;
      String header;
      String subHeader;
      String imgUrl;
    
      Feature({this.name, this.color, this.header, this.subHeader, this.imgUrl});
    }
    
    List<Feature> featuredList = [
      Feature(
          name: "a",
          color: Colors.pink,
          header: "ah",
          subHeader: "a sub",
          imgUrl: "https://picsum.photos/250?image=9"),
      Feature(
          name: "b",
          color: Colors.blue,
          header: "bh",
          subHeader: "b sub",
          imgUrl: "https://picsum.photos/250?image=10"),
      Feature(
          name: "c",
          color: Colors.yellow,
          header: "ch",
          subHeader: "c sub",
          imgUrl: "https://picsum.photos/250?image=11")
    ];
    
    class WidgetFeatured extends StatefulWidget {
      @override
      _WidgetFeaturedState createState() => _WidgetFeaturedState();
    }
    
    class _WidgetFeaturedState extends State<WidgetFeatured> {
      int _currentPage = 0;
    
      final PageController _pageController = PageController(
        initialPage: 0,
      );
    
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          Timer.periodic(Duration(seconds: 4), (Timer timer) {
            if (_currentPage < 3) {
              _currentPage++;
            } else {
              _currentPage = 0;
            }
    
            if(_pageController.hasClients) {
              _pageController.animateToPage(
                _currentPage,
                duration: Duration(milliseconds: 400),
                curve: Curves.easeInCubic,
              );
            }
    
          });
        });
      }
    
      @override
      void dispose() {
        super.dispose();
        _pageController.dispose();
      }
    
      _onPageChanged(int index) {
        setState(() {
          _currentPage = index;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          height: 200,
          child: PageView.builder(
            physics: BouncingScrollPhysics(),
            scrollDirection: Axis.horizontal,
            controller: _pageController,
            onPageChanged: _onPageChanged,
            itemBuilder: (context, index) => WidgetFeaturedItem(index),
            itemCount: featuredList.length,
          ),
        );
      }
    }
    
    class WidgetFeaturedItem extends StatelessWidget {
      final int indexItem;
    
      WidgetFeaturedItem(this.indexItem);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: const EdgeInsets.all(20),
          color: featuredList[indexItem].color,
          width: double.infinity,
          height: 180,
          child: Stack(
            children: <Widget>[
              Row(
                children: <Widget>[
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        featuredList[indexItem].header,
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ),
                      Text(
                        featuredList[indexItem].subHeader,
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ),
                      FlatButton(
                        onPressed: () {},
                        padding: const EdgeInsets.symmetric(
                          horizontal: 15,
                          vertical: 3,
                        ),
                        color: Theme.of(context).primaryColor,
                        child: Text(
                          'Order now',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 12,
                            fontWeight: FontWeight.w100,
                          ),
                        ),
                      ),
                    ],
                  ),
                  Image.network(
                    featuredList[indexItem].imgUrl,
                    height: 120,
                    width: 120,
                    //width: 335,
                    fit: BoxFit.cover,
                  ),
                ],
              )
            ],
          ),
        );
      }
    }
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Expanded(child: WidgetFeatured()),
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }