Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make `NestedScrollView` only scroll its body when necessary

Tags:

flutter

I'm using NestedScrollView.headerSliverBuilder property to reproduce the same iOS behavior of collapsing the page title when scrolling the screen content, like the GIF below illustrate

enter image description here

And it's working really good so far. The problem is that, when the screen content is lower than the screen bounds, I would like to block the NestedScrollView body scroll, since in theory it wouldn't be necessary to scroll because all the content is visible (just like the GIF example).

Here's the code I'm using in the GIF example:

@override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [
          SliverOverlapAbsorber(
            handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            sliver: SliverSafeArea(
              top: false,
              bottom: false,
              sliver: CupertinoSliverNavigationBar(largeTitle: Text('Page Title')),
            ),
          ),
        ],
        body: Material(
          child: SafeArea(
            top: false,
            child: Center(child: Container(color: Colors.red, height: 50)),
          ),
        ),
      ),
    );
  }
like image 200
GGirotto Avatar asked Aug 31 '25 17:08

GGirotto


2 Answers

Use CustomScrollView instead of NestedScrollView:

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: CustomScrollView(
        slivers: [
          const SliverSafeArea(
            top: false,
            bottom: false,
            sliver:
                CupertinoSliverNavigationBar(largeTitle: Text('Page Title')),
          ),
          SliverToBoxAdapter(
            child: Material(
              child: SafeArea(
                top: false,
                child: Center(child: Container(color: Colors.red, height: 50)),
              ),
            ),
          ),
        ],
      ),
    );
  }
like image 172
Mahdi Arabpour Avatar answered Sep 02 '25 08:09

Mahdi Arabpour


I would recommend to stick with the builtin behaviors To reproduce this kind of reducing app bar with better animation, fluidity and integrated ClampingScroll you could use a CustomScrollView with a SliverAppBar.

Feel free to change the itemCount to see the behavior when its scrolling, also change the FlexibleSpaceBar to reproduce the AppBar you want. You can add background image and more.

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            pinned: true,
            floating: true,
            snap: true,
            expandedHeight: 200.0,
            flexibleSpace: FlexibleSpaceBar(
              title: Text("Twitter-like AppBar"),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              childCount: 3,
              (context, index) => ListTile(
                title: Text('Item #${index}'),
              ),
            ),
          ),
        ],
      ),
    );
  }
like image 40
Colin Lazarini Avatar answered Sep 02 '25 07:09

Colin Lazarini