title: Flutter Exception: ScrollController attached to multiple scroll views
body: <p>My Flutter application is throwing an exception (ScrollController attached to multiple scroll views) when navigating away from a page that has a <code>ScrollController</code> to control a <code>NestedScrollView</code> and I am not sure what I am doing wrong.</p>
  
  <p>I have recreated the exception with a simple example below. I can navigate from <code>FirstPage</code> to <code>SecondPage</code> (and optionally back) just fine, but when I navigate from <code>SecondPage</code> to <code>ThirdPage</code> the exception is thrown. The <code>SecondPage</code> is the page that contains my custom <code>CollapsingAppBarPage</code> widget which I assume has the problem. <code>CollapsingAppBarPage</code> is simplified in this example, but in my real app it changes colors/sizes of components based on the scroll position. In this example, the exception happens when <code>_scrollController.offset</code> is called as the navigation begins to the <code>ThirdPage</code>. Also, I know FirstPage and ThirdPage could be Stateless instead of StatefulWidgets but I wanted to make it as much like my app as possible. Here is my fully working example.</p>
  
  <pre><code>import 'package:flutter/material.dart';
  
  void main() =&gt; runApp(MyApp());
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Demo',
        home: FirstPage(),
      );
    }
  }
  
  class FirstPage extends StatefulWidget {
    @override
    _FirstPageState createState() =&gt; _FirstPageState();
  }
  
  class _FirstPageState extends State&lt;FirstPage&gt; {
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text("First Page"),
        ),
        body: Center(
          child: RaisedButton(
            child: Text("Navigate Next"),
            onPressed: () async {
              await Navigator.push(context,
                  MaterialPageRoute(builder: (context) =&gt; SecondPage())
              );
            },
          ),
        ),
      );
    }
  }
  
  class SecondPage extends StatefulWidget {
    @override
    _SecondPageState createState() =&gt; _SecondPageState();
  }
  
  class _SecondPageState extends State&lt;SecondPage&gt; {
    @override
    Widget build(BuildContext context) {
      return Material(
        child: CollapsingAppBarPage(
          titleText: "Second Page",
          bodyCreator: (context) {
            return ListView(
              children: &lt;Widget&gt;[
                Center(
                  child: RaisedButton(
                    child: Text("Navigate Next"),
                    onPressed: () async {
                      await Navigator.push(context,
                          MaterialPageRoute(builder: (context) =&gt; ThirdPage())
                      );
                    },
                  ),
                )
              ],
            );
          },
        ),
      );
    }
  }
  
  class ThirdPage extends StatefulWidget {
    @override
    _ThirdPageState createState() =&gt; _ThirdPageState();
  }
  
  class _ThirdPageState extends State&lt;ThirdPage&gt; {
    @override
    Widget build(BuildContext context) {
      return Scaffold(
          appBar: AppBar(
              title: Text("Third Page")
          ),
          body: Container()
      );
    }
  }
  
  typedef CollapsingAppBarBodyCreator = Widget Function(BuildContext context);
  
  class CollapsingAppBarPage extends StatefulWidget {
  
    final String titleText;
    final CollapsingAppBarBodyCreator bodyCreator;
  
    CollapsingAppBarPage({
      Key key,
      this.titleText,
      @required this.bodyCreator,
    }) : super(key: key);
  
    @override
    _CollapsingAppBarPageState createState() =&gt; _CollapsingAppBarPageState();
  }
  
  class _CollapsingAppBarPageState extends State&lt;CollapsingAppBarPage&gt; {
  
    static const _kExpandedHeight = 200.0;
  
    ScrollController _scrollController;
  
    @override
    void initState() {
      super.initState();
      _scrollController = ScrollController()
        ..addListener(() {
          setState(() {
            // force a refresh so the app bar can be updated
          });
        });
    }
  
    @override
    void dispose() {
      _scrollController.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return NestedScrollView(
        controller: _scrollController,
        headerSliverBuilder: _createSliverAppBar,
        body: widget.bodyCreator(context),
      );
    }
  
    List&lt;Widget&gt; _createSliverAppBar(BuildContext context, bool innerBoxIsScrolled) {
      // change the icon color as the page scrolls
      var collapsePercent = _getAppBarCollapsePercent();
      int rgb = ((1.0 - collapsePercent) * 255).round();
      var color = Color.fromARGB(255, rgb, rgb, rgb);
  
      return &lt;Widget&gt;[
        SliverAppBar(
          expandedHeight: _kExpandedHeight,
          pinned: true,
          iconTheme: IconThemeData(color: color),
          title: Text(widget.titleText),
        )
      ];
    }
  
    double _getAppBarCollapsePercent() {
      if (!_scrollController.hasClients)
        return 0.0;
  
      return (_scrollController.offset / (_kExpandedHeight - kToolbarHeight)).clamp(0.0, 1.0);
    }
  }
  </code></pre>
  
  <p>Here is a truncated trace of the exception:</p>
  
  <pre><code>flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
  flutter: The following assertion was thrown building Builder(dirty):
  flutter: ScrollController attached to multiple scroll views.
  flutter: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 111 pos 12:
  flutter: '_positions.length == 1'
  flutter:
  flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
  flutter: more information in this error message to help you determine and fix the underlying cause.
  flutter: In either case, please report this assertion by filing a bug on GitHub:
  flutter:   https://github.com/flutter/flutter/issues/new?template=BUG.md
  flutter:
  flutter: When the exception was thrown, this was the stack:
  flutter: #2      ScrollController.position (package:flutter/src/widgets/scroll_controller.dart:111:12)
  flutter: #3      ScrollController.offset (package:flutter/src/widgets/scroll_controller.dart:118:24)
  flutter: #4      _CollapsingAppBarPageState._getAppBarCollapsePercent (package:flutter_scroll_test/main.dart:160:31)
  flutter: #5      _CollapsingAppBarPageState._createSliverAppBar (package:flutter_scroll_test/main.dart:142:27)
  flutter: #6      NestedScrollView._buildSlivers (package:flutter/src/widgets/nested_scroll_view.dart:271:20)
  flutter: #7      _NestedScrollViewState.build.&lt;anonymous closure&gt; (package:flutter/src/widgets/nested_scroll_view.dart:347:29)
  flutter: #8      Builder.build (package:flutter/src/widgets/basic.dart:5736:41)
  flutter: #9      StatelessElement.build (package:flutter/src/widgets/framework.dart:3774:28)
  flutter: #10     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
  </code></pre>