Skip to content

Instantly share code, notes, and snippets.

@awatson32
Last active June 22, 2022 20:04
Show Gist options
  • Save awatson32/d0a6808dc52e6eb77bfc8b94abbdadb1 to your computer and use it in GitHub Desktop.
Save awatson32/d0a6808dc52e6eb77bfc8b94abbdadb1 to your computer and use it in GitHub Desktop.
expandable appbar
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<String>.generate(40, (i) => 'Item $i'),
));
}
class MyApp extends StatefulWidget {
final List<String> items;
const MyApp({Key? key, required this.items}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
late final AnimationController animationController;
late final Animation animation;
bool expanded = false;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 400));
animation = Tween<double>(begin: 90, end: 120).animate(animationController);
animationController.forward();
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
extendBody: true,
extendBodyBehindAppBar: true,
appBar: AnimatedAppBar(
title: const Text(
'Expandable AppBar',
),
leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)),
),
body: ListView.builder(
itemCount: widget.items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(widget.items[index]),
);
}),
),
);
}
}
class AnimatedAppBar extends StatefulWidget implements PreferredSizeWidget {
final Widget? title;
final double? height;
final List<Widget>? actions;
final Widget? leading;
final Widget? bottom;
final double? opacity;
final Widget? flexibleSpace;
const AnimatedAppBar(
{Key? key,
this.title,
this.height,
this.actions,
this.leading,
this.opacity,
this.flexibleSpace,
this.bottom})
: super(key: key);
@override
Size get preferredSize => const Size.fromHeight(120);
@override
State<AnimatedAppBar> createState() => _AnimatedAppBarState();
}
class _AnimatedAppBarState extends State<AnimatedAppBar>
with SingleTickerProviderStateMixin {
static const Duration duration = Duration(milliseconds: 300);
bool selected = false;
double get size => selected ? 160 : 110;
double get opacity => selected ? 1.0 : 0.0;
void toggleExpanded() {
setState(() {
selected = !selected;
});
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: duration,
curve: Curves.ease,
alignment: Alignment.bottomCenter,
height: size,
child: AppBar(
automaticallyImplyLeading: false,
elevation: 2,
backgroundColor: Colors.blue,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15))),
centerTitle: true,
title: widget.title,
leading: widget.leading,
actions: [
IconButton(
onPressed: () => toggleExpanded(),
icon: const Icon(
Icons.tune_rounded,
))
],
flexibleSpace: AnimatedOpacity(
opacity: opacity,
duration: duration,
curve: Curves.ease,
child: Container(
padding: const EdgeInsets.only(bottom: 6),
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero)),
onPressed: () {},
child: const Text('ALL',
style: TextStyle(color: Colors.white))),
IconButton(
iconSize: 20,
color: Colors.white,
icon: const Icon(Icons.video_call),
onPressed: () {},
),
IconButton(
iconSize: 20,
color: Colors.white,
onPressed: () {},
icon: const Icon(Icons.headphones)),
IconButton(
iconSize: 20,
color: Colors.white,
onPressed: () {},
icon: const Icon(Icons.menu_book_sharp)),
IconButton(
iconSize: 20,
color: Colors.white,
onPressed: () {},
icon: const Icon(Icons.search))
]),
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment