18

i make a sliverappbar, and i want to put a card over this sliverappbar. How can i put a card over the sliverappbar and this card collapse with the sliverappbar?

The card should stay half in appbar and half in the 'body'

CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          expandedHeight: 100.0,
          floating: true,
          snap: true,
          backgroundColor: Colors.green,
          elevation: 0.0,
          flexibleSpace: FlexibleSpaceBar(
            title: const Text(
              "test",
              style: TextStyle(color: Colors.white, fontSize: 20.0),
            ),
            centerTitle: true,
            background: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Stack(
                  children: <Widget>[
                    Container(
                      height: 60.0,
                      color: Colors.black,
                    )
                  ],
                )
              ],
            )
          ),
        SliverFillRemaining(
          child: new Text("data"),
        )
      ],
    ),
Leonardo M
  • 197
  • 1
  • 1
  • 8

1 Answers1

45

You can do it using SliverPersistentHeaderDelegate and Stack widget, check my sample :

    class PlayingSliversState extends State<PlayingSlivers> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: CustomScrollView(
              slivers: <Widget>[
                SliverPersistentHeader(
                  pinned: true,
                  floating: true,
                  delegate: CustomSliverDelegate(
                    expandedHeight: 120,
                  ),
                ),
                SliverFillRemaining(
                  child: Center(
                    child: Text("data"),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }

    class CustomSliverDelegate extends SliverPersistentHeaderDelegate {
      final double expandedHeight;
      final bool hideTitleWhenExpanded;

      CustomSliverDelegate({
        @required this.expandedHeight,
        this.hideTitleWhenExpanded = true,
      });

      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        final appBarSize = expandedHeight - shrinkOffset;
        final cardTopPosition = expandedHeight / 2 - shrinkOffset;
        final proportion = 2 - (expandedHeight / appBarSize);
        final percent = proportion < 0 || proportion > 1 ? 0.0 : proportion;
        return SizedBox(
          height: expandedHeight + expandedHeight / 2,
          child: Stack(
            children: [
              SizedBox(
                height: appBarSize < kToolbarHeight ? kToolbarHeight : appBarSize,
                child: AppBar(
                  backgroundColor: Colors.green,
                  leading: IconButton(
                    icon: Icon(Icons.menu),
                    onPressed: () {},
                  ),
                  elevation: 0.0,
                  title: Opacity(
                      opacity: hideTitleWhenExpanded ? 1.0 - percent : 1.0,
                      child: Text("Test")),
                ),
              ),
              Positioned(
                left: 0.0,
                right: 0.0,
                top: cardTopPosition > 0 ? cardTopPosition : 0,
                bottom: 0.0,
                child: Opacity(
                  opacity: percent,
                  child: Padding(
                    padding: EdgeInsets.symmetric(horizontal: 30 * percent),
                    child: Card(
                      elevation: 20.0,
                      child: Center(
                        child: Text("Header"),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        );
      }

      @override
      double get maxExtent => expandedHeight + expandedHeight / 2;

      @override
      double get minExtent => kToolbarHeight;

      @override
      bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
        return true;
      }
    }

Result:

enter image description here

diegoveloper
  • 93,875
  • 20
  • 236
  • 194
  • 5
    where you learn all this stuff, its really cool ,I can't get any tutorial relating it – Avnish Nishad Oct 02 '19 at 18:27
  • @Avnishkumar https://medium.com/flutter-community/flutter-increase-the-power-of-your-appbar-sliverappbar-c4f67c4e076f – diegoveloper Oct 02 '19 at 18:55
  • 1
    Is there a way to make to lower half responsive. I mean since Stack doesn't allow overflowing part of any widget to interact with user, how can I put some clickable items there? – Md Azharuddin Dec 22 '19 at 15:28
  • How to use setState here and use variables in example above, if someone can clarify that please. Thanks – Maka May 22 '20 at 22:14
  • You need a StatefulWidget – diegoveloper May 22 '20 at 22:16
  • Hi @diegoveloper. This is really great. But when I scroll up the action button of app bar is not able to click? do you know what is the problem? – Visal Sambo Oct 21 '20 at 15:41
  • Thank you @diegoveloper for the wonderful explanation! If we've to remove the fade out transition of the card, would we be able to do it in sliverappbar – Katelyn Raphael Mar 04 '22 at 14:21
  • @VisalSambo Are you able to achieve it? I am trying to put icons in my card too but unable to click on it too – ZXERSTON Jan 15 '23 at 05:19