Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Collapsible Appbar with custom layout and animation

I am trying to create an app bar that looks like the following image when expanded

enter image description here

When collapsing I only need the initial column of text to be available in the app bar, so the image should fade away and the text column to animate and become the Appbar title

I have tried using SliverAppBar with a custom scroll view but the Flexible space's title is not looking good also I don't know how to make the image disappear alone and show only the text when collapsed.

As of now, this is the expanded state

enter image description here

And when I try to collapse it, this happens

enter image description here

Here's the code for the same

CustomScrollView(
    slivers: [
      SliverAppBar(
          pinned: true,
          leading: GestureDetector(
            onTap: () => Get.back(),
            child: const Icon(
              Icons.arrow_back,
              color: Colors.black,
            ),
          ),
          flexibleSpace: FlexibleSpaceBar(
            title: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: Row(
                children: [
                  const Expanded(
                    child: Text.rich(
                      TextSpan(
                          text: "Buffet Deal\n",
                          style:
                              TextStyle(color: Colors.black, fontSize: 14),
                          children: [
                            TextSpan(
                              text: "Flash Deal",
                              style: TextStyle(
                                  color: Colors.black, fontSize: 10),
                            ),
                          ]),
                    ),
                  ),
                  if (_model.imgUrl != null)
                    CachedNetworkImage(
                      imageUrl: _model.imgUrl!,
                    ),
                  const SizedBox(
                    width: 18,
                  )
                ],
              ),
            ),
          ),
          expandedHeight: Get.height * 0.2,
          backgroundColor: const Color(0xFFFFF4F4)),
      SliverToBoxAdapter(
        child: Container()
      )
    ],
  ),

Your help is appreciated. Thanks in advance

like image 269
Fardeen Khan Avatar asked Oct 27 '25 08:10

Fardeen Khan


1 Answers

To make the SliverAppBar's flexible space image disappear whenever the expanded space collapse just use the FlexibleSpaceBar.background property.

To solve the overlapping text just wrap the FlexibleSpaceBar around a LayoutBuilder to get if it's expanded or not and adjust the text positioning.

Check out the result below (Also, the live demo on DartPad):

Screenshot

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final expandedHeight = MediaQuery.of(context).size.height * 0.2;
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            pinned: true,
            leading: GestureDetector(
              onTap: () => {},
              child: const Icon(
                Icons.arrow_back,
                color: Colors.black,
              ),
            ),
            flexibleSpace: LayoutBuilder(builder: (context, constraints) {
              final fraction =
                  max(0, constraints.biggest.height - kToolbarHeight) /
                      (expandedHeight - kToolbarHeight);
              return FlexibleSpaceBar(
                title: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Row(
                    children: [
                      Expanded(
                        child: Padding(
                          padding: EdgeInsets.only(left: 24 * (1 - fraction)),
                          child: const Text.rich(
                            TextSpan(
                                text: "Buffet Deal\n",
                                style: TextStyle(
                                    color: Colors.black, fontSize: 14),
                                children: [
                                  TextSpan(
                                    text: "Flash Deal",
                                    style: TextStyle(
                                        color: Colors.black, fontSize: 10),
                                  ),
                                ]),
                          ),
                        ),
                      ),
                      const SizedBox(width: 18)
                    ],
                  ),
                ),
                background: Align(
                  alignment: Alignment.centerRight,
                  child: Image.network(
                    "https://source.unsplash.com/random/400x225?sig=1&licors",
                  ),
                ),
              );
            }),
            expandedHeight: MediaQuery.of(context).size.height * 0.2,
            backgroundColor: const Color(0xFFFFF4F4),
          ),
          const SliverToBoxAdapter(child: SizedBox(height: 1000))
        ],
      ),
    );
  }
}
like image 189
lepsch Avatar answered Oct 28 '25 23:10

lepsch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!