Search code examples
flutterflutter-sliverflutter-sliverappbarflutter-3.0

SliverAppBar have an image as a background, circle avatar and title


I am trying to achieve something similar to this where I have background, circle avatar, and title, and when scrolling up the avatar disappears but the title remains. What I have been able to do is get the background image applied, and the sliver title to remain but I cannot work out how to have title outside the FlexibleSpaceBar, nor how to have the CircleAvatar 50% over the background.

enter image description here

SliverAppBar.large(
          expandedHeight: 200.0,
          floating: true,
          pinned: true,
          snap: true,
          flexibleSpace: FlexibleSpaceBar(
            title: _buildProfileName(user),
            background: Stack(
              children: [
                Container(
                  decoration: const BoxDecoration(
                    image: DecorationImage(
                      colorFilter: ColorFilter.mode(
                          Colors.black54, BlendMode.darken),
                      image: AssetImage(
                          "assets/images/landing/hedge-trimmer.jpg"),
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
                Positioned(
                  top:
                      175.0, // (background container size) - (circle height / 2)
                  left: MediaQuery.of(context).size.width / 2 - 50,
                  child: Center(
                    child: CircleAvatar(
                      child: CircleAvatar(
                        backgroundImage: (user.profileImageUrl!.isEmpty
                                ? const AssetImage('assets/images/Logo.png')
                                : CachedNetworkImageProvider(
                                    user.profileImageUrl!))
                            as ImageProvider<Object>?,
                        radius: 45,
                      ),
                      radius: 50,
                      backgroundColor: Colors.white,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),

This above produces something that is close to what I am after just not completely

enter image description here


Solution

  • I think you are almost there. You can expand the SliverAppBar to include the bottom white space below. Here is the example code:

    class CustomSliverAppBar extends StatelessWidget {
      const CustomSliverAppBar({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        final expandedHeight = 500.0;
        final collapsedHeight = 60.0;
        return CustomScrollView(
          slivers: [
            SliverAppBar(
              expandedHeight: expandedHeight,
              collapsedHeight: collapsedHeight,
              floating: true,
              pinned: true,
              snap: true,
              backgroundColor: Colors.white,
              flexibleSpace: FlexibleSpaceBar(
                collapseMode: CollapseMode.pin,
                title: Text('Title',
                    style: TextStyle(fontSize: 28, color: Colors.black)),
                background: Stack(
                  children: [
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                        height: expandedHeight - collapsedHeight - 80,
                        decoration: const BoxDecoration(
                          image: DecorationImage(
                            colorFilter:
                                ColorFilter.mode(Colors.black54, BlendMode.darken),
                            image: NetworkImage('https://picsum.photos/1024'),
                            fit: BoxFit.cover,
                          ),
                        ),
                      ),
                    ),
                    Positioned(
                      bottom: collapsedHeight + 30,
                      left: MediaQuery.of(context).size.width / 2 - 50,
                      child: Container(
                        padding: EdgeInsets.all(5),
                        decoration: ShapeDecoration(
                          color: Colors.white,
                          shape: CircleBorder(),
                        ),
                        child: CircleAvatar(
                          backgroundImage:
                              NetworkImage('https://picsum.photos/256'),
                          radius: 45,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            for (int i = 0; i < 10; i++)
              SliverToBoxAdapter(
                child: Container(
                  height: 200,
                  color: i % 2 == 0 ? Colors.grey : Colors.grey.shade300,
                ),
              )
          ],
        );
      }
    }
    

    enter image description here