2

I'm trying to auto scroll to the end of a SliverList that is inside a CustomScrollView. SliverList itself doesn't have a controller property so I have to pass a ScrollController to the CustomScrollView.

The problem is when I pass a controller to the CustomScrollView its behavior changes and it's no longer scrolls the outer list and would not cause a collapsed SliverAppBar widget. How can I auto scroll SliverList and also keep the behavior of CustomScrollView as before?

Here is my code:

class _MyHomePageState extends State<MyHomePage> {
  ScrollController _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            _scrollController.animateTo(
              _scrollController.position.maxScrollExtent,
              curve: Curves.easeOut,
              duration: const Duration(seconds: 1),
            );
          },
        ),
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                expandedHeight: 230.0,
                pinned: true,
                flexibleSpace: FlexibleSpaceBar(
                  title: Text('SliverAppBar Expand'),
                ),
              )
            ];
          },
          body: CustomScrollView(
                //When controller is passed to CustomScrollView, its behavior changes
                // controller: _scrollController,  
                slivers: [
                  //Some widgets are here
                  SliverList(
                    delegate: SliverChildBuilderDelegate(
                      (context, index) {
                        return Container(
                          height: 80,
                          color: Colors.primaries[index % Colors.primaries.length],
                          alignment: Alignment.center,
                          child: Text(
                            'Item : $index',
                          ),
                        );
                      },
                      childCount: 20,
                    ),
                  ),
                ],
              ),
            ) ,
         );
      }
    }

1 Answer 1

5

I think you may notice the explanation of the example here: NestedScrollView class

// The "controller" and "primary" members should be left
// unset, so that the NestedScrollView can control this
// inner scroll view.
// If the "controller" property is set, then this scroll
// view will not be associated with the NestedScrollView.
// The PageStorageKey should be unique to this ScrollView;
// it allows the list to remember its scroll position when
// the tab view is not on the screen.

and

// This Builder is needed to provide a BuildContext that is
// "inside" the NestedScrollView, so that
// sliverOverlapAbsorberHandleFor() can find the
// NestedScrollView.

The correct way is to get the controller used by CustomScrollView, not to add a new one to it.

It can be done by adding a Builder above the CustomScrollView) and assign the controller to _scrollController.

...
  body: NestedScrollView(
    ...
    body: Builder(
      builder: (context){
        _scrollController = PrimaryScrollController.of(context);
        return CustomScrollView(
          ...
      },
    ),
  ),
...
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for such a detailed answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.