Search code examples
flutterflutter-widgetflutter-appbarsliverappbarflutter-sliverappbar

How to put a Card widget inside a SliverAppBar?


I'm a beginner in Flutter. I'm trying to make widget like this. Unfortunately I still struggled to implement them. I've tried using flexible space bar with some alignment in the container. But it didn't go as what I want. Is there any way to put that card on a SliverAppBar? Here is my code.

Header.dart

  Widget build(BuildContext context) {
    return SliverAppBar(
      expandedHeight: 25.h,
      backgroundColor: celticBlue,
      actions: [
        IconButton(
          icon: const Icon(Icons.more_vert),
          onPressed: () {},
        ),
      ],
      title: Text('Quran', style: whiteHeading16),
      centerTitle: true,
      shadowColor: danube,
      pinned: true,
      elevation: 1,
      shape: const ContinuousRectangleBorder(
        borderRadius: BorderRadius.only(
          bottomLeft: Radius.elliptical(100, 50),
          bottomRight: Radius.elliptical(50, 100),
        ),
      ),
      flexibleSpace: Padding(
        padding: const EdgeInsets.all(25),
        child: Container(
          color: Colors.redAccent,
          alignment: Alignment.bottomCenter,
          height: 15.h,
        ),
      ),
    );
  }

Here's the result


Solution

  • 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 You can edit this code as per your wish then see

    enter image description here