animated_bottom_navigation_bar 0.3.1+1 animated_bottom_navigation_bar: ^0.3.1+1 copied to clipboard
Animated Bottom Navigation Bar Widget implementation inspired by https://dribbble.com/shots/7134849-Simple-Tab-Bar-Animation
import 'dart:async';
import 'package:animated_bottom_navigation_bar/animated_bottom_navigation_bar.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:circular_reveal_animation/circular_reveal_animation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Animated Navigation Bottom Bar'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
final autoSizeGroup = AutoSizeGroup();
var _bottomNavIndex = 0; //default index of first screen
AnimationController _animationController;
Animation<double> animation;
CurvedAnimation curve;
final iconList = <IconData>[
Icons.brightness_5,
Icons.brightness_4,
Icons.brightness_6,
Icons.brightness_7,
];
@override
void initState() {
super.initState();
final systemTheme = SystemUiOverlayStyle.light.copyWith(
systemNavigationBarColor: HexColor('#373A36'),
systemNavigationBarIconBrightness: Brightness.light,
);
SystemChrome.setSystemUIOverlayStyle(systemTheme);
_animationController = AnimationController(
duration: Duration(seconds: 1),
vsync: this,
);
curve = CurvedAnimation(
parent: _animationController,
curve: Interval(
0.5,
1.0,
curve: Curves.fastOutSlowIn,
),
);
animation = Tween<double>(
begin: 0,
end: 1,
).animate(curve);
Future.delayed(
Duration(seconds: 1),
() => _animationController.forward(),
);
}
@override
Widget build(BuildContext context) {
return Theme(
data: ThemeData.dark(),
child: Scaffold(
extendBody: true,
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.white),
),
backgroundColor: HexColor('#373A36'),
),
body: NavigationScreen(
iconList[_bottomNavIndex],
),
floatingActionButton: ScaleTransition(
scale: animation,
child: FloatingActionButton(
elevation: 8,
backgroundColor: HexColor('#FFA400'),
child: Icon(
Icons.brightness_3,
color: HexColor('#373A36'),
),
onPressed: () {
_animationController.reset();
_animationController.forward();
},
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
itemCount: iconList.length,
tabBuilder: (int index, bool isActive) {
final color = isActive ? HexColor('#FFA400') : Colors.white;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
iconList[index],
size: 24,
color: color,
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AutoSizeText(
"brightness $index",
maxLines: 1,
style: TextStyle(color: color),
group: autoSizeGroup,
),
)
],
);
},
backgroundColor: HexColor('#373A36'),
activeIndex: _bottomNavIndex,
splashColor: HexColor('#FFA400'),
notchAndCornersAnimation: animation,
splashSpeedInMilliseconds: 300,
notchSmoothness: NotchSmoothness.defaultEdge,
gapLocation: GapLocation.center,
leftCornerRadius: 32,
rightCornerRadius: 32,
onTap: (index) => setState(() => _bottomNavIndex = index),
),
),
);
}
}
class NavigationScreen extends StatefulWidget {
final IconData iconData;
NavigationScreen(this.iconData) : super();
@override
_NavigationScreenState createState() => _NavigationScreenState();
}
class _NavigationScreenState extends State<NavigationScreen> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> animation;
@override
void didUpdateWidget(NavigationScreen oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.iconData != widget.iconData) {
_startAnimation();
}
}
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
);
animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
_controller.forward();
super.initState();
}
_startAnimation() {
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
);
animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.white,
child: Center(
child: CircularRevealAnimation(
animation: animation,
centerOffset: Offset(80, 80),
maxRadius: MediaQuery.of(context).size.longestSide * 1.1,
child: Icon(
widget.iconData,
color: HexColor('#FFA400'),
size: 160,
),
),
),
);
}
}
class HexColor extends Color {
HexColor(final String hexColor) : super(_getColorFromHex(hexColor));
static int _getColorFromHex(String hexColor) {
hexColor = hexColor.toUpperCase().replaceAll('#', '');
if (hexColor.length == 6) {
hexColor = 'FF' + hexColor;
}
return int.parse(hexColor, radix: 16);
}
}