Fardeen Khan
Fardeen Khan

Reputation: 1010

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

Upvotes: 4

Views: 2815

Answers (1)

lepsch
lepsch

Reputation: 10319

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))
        ],
      ),
    );
  }
}

Upvotes: 3

Related Questions