Search code examples
flutternestedscrollviewcustomscrollviewflutter-sliverappbar

How to make one part of body scrollable and other as fixed when using SliverAppBar


I'm trying to make a UI in flutter wherein I'm using SliverAppBar(I mention this because I need to use either CustomScrollView or NestedScrollView) and now in the body, I was to make the first two elements not scroll when they reach the top of the screen while the bottom list does. Using CustomScrollView, it either scrolls as a whole or does not at all(Appbar included). In NestedScrollView, if i use NeverScrollableScrollPhysics, the appbar scrolls and the body does not. Now I can either make the whole body scrollable or i get a pixel error. Please help me.

I have added the NestedScrollView code below. I need the search bar and the go to cart container to get fixed at the top once the sliver bar disappears.

NestedScrollView(
         physics: NeverScrollableScrollPhysics(),
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              backgroundColor: Color(0xffececec),
              shadowColor: Colors.transparent,
              iconTheme: IconThemeData(color: Colors.black),
              pinned: false,
              centerTitle: true,
              expandedHeight: 200.0,
              floating: false,
              forceElevated: innerBoxIsScrolled,
              // snap: true,
              flexibleSpace: SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: Container(
                    padding: EdgeInsets.only(top: 80),
                    child: Row(
                      children: [
                        banner(
                            image),
                        banner(
                            image),
                        banner(
                           image),
                      ],
                    ),
                  )),
              actions: [
                InkWell(
                  onTap: () {
                    Navigator.push(
                        context, MaterialPageRoute(builder: (_) => Cart()));
                  },
                  child: Icon(
                    Icons.shopping_cart,
                    color: Colors.black,
                  ),
                ),
                SizedBox(width: Units.width(context) * 0.03),
              ],
            )
          ];
        },
        body: SingleChildScrollView(
          physics: NeverScrollableScrollPhysics(),
          child: Column(
            children: [
              Row(
                children: [
                  Text('Search'),
                         Icon(
                          FontAwesomeIcons.search,
                          color: Colors.white,
                        ),
                     
                ],
              ),
              Container(
                height: Units.height(context) * 0.1,
                width: Units.height(context) * 0.17,
               
                child: Text(
                  "Go to cart",
                  style: TextStyle(
                      fontSize: Units.regularText(context) * 0.9,
                      fontWeight: FontWeight.bold),
                ),
              ),
              ListView(
                shrinkWrap: true,
                physics: AlwaysScrollableScrollPhysics(),
                children: [
                  Center(
                    child: Wrap(
                      children: [
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                        lappyCard(context),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),

Solution

  • An alternative to SliverAppBar to get the UX (I think) that you're after, is using a package called sticky_headers

    Hopefully this very basic example can demonstrate the functionality that I think you are looking for:

    First, install the package:

      sticky_headers: ^0.2.0
    

    Then import: import 'package:sticky_headers/sticky_headers.dart';

    Finally, implementation:

    Scaffold(
      appBar: AppBar(title: Text("Sticky Headers Example")),
      body: ListView(
        children: [
          Container(color:  Colors.yellow, height: 100,  width: double.infinity, child: Text("one"),),
          StickyHeader(
            header:
            Column(
              children: [
                Container(color:  Colors.green, height: 100, width: double.infinity, child: Text("two"),),
                Container(color:  Colors.blue, height: 100, width: double.infinity, child: Text("three"),),
              ],
            ),
            content: Column(
              children: [
                Container(color:  Colors.red, height: 600,  width: double.infinity, child: Text("four"),),
                Container(color:  Colors.orange, height: 600,  width: double.infinity, child: Text("five"),)
              ],
            ),
          ),
        ],
      ),
    );
    

    Note: You can also include multiple sticky headers:

    Scaffold(
      appBar: AppBar(title: Text("Sticky Headers Example")),
      body: ListView(
        children: [      
          StickyHeader(
            header: Container(color:  Colors.green, height: 100, width: double.infinity, child: Text("six"),),
            content: Container(color:  Colors.red, height: 300,  width: double.infinity, child: Text("seven"),),
          ),
          StickyHeader(
            header: Container(color:  Colors.purple, height: 100, width: double.infinity, child: Text("eight"),),
            content: Container(color:  Colors.blue, height: 800,  width: double.infinity, child: Text("nine"),),
          ),
        ],
      ),
    );