Instantly share code, notes, and snippets.
Created
December 17, 2024 01:20
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save neganngdev/9340f4c45d3c9e505cc7278b21706d3b to your computer and use it in GitHub Desktop.
Passant Navbar - Animated Floating Action Menu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| void main() { | |
| runApp(const MyApp()); | |
| } | |
| class MyApp extends StatelessWidget { | |
| const MyApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| title: 'Flutter UI Demo', | |
| theme: ThemeData(primarySwatch: Colors.blue), | |
| home: const HomeScreen(), | |
| ); | |
| } | |
| } | |
| class HomeScreen extends StatefulWidget { | |
| const HomeScreen({super.key}); | |
| @override | |
| State<HomeScreen> createState() => _HomeScreenState(); | |
| } | |
| class _HomeScreenState extends State<HomeScreen> | |
| with SingleTickerProviderStateMixin { | |
| late final AnimationController _controller = AnimationController( | |
| duration: const Duration(milliseconds: 400), | |
| vsync: this, | |
| ); | |
| late final Animation<double> _rotationAngle = | |
| Tween<double>(begin: 0, end: 0.5).animate( | |
| CurvedAnimation(parent: _controller, curve: Curves.easeInOut), | |
| ); | |
| late final Animation<Color?> _centerIconBackgroundColor = ColorTween( | |
| begin: const Color(0xFFFF3841), | |
| end: const Color(0xFFEAEAEA), | |
| ).animate(_controller); | |
| late final Animation<Color?> _centerIconForegroundColor = ColorTween( | |
| begin: Colors.white, | |
| end: Colors.black, | |
| ).animate(_controller); | |
| late final Animation<double?> _bottomBarActionMenuTopPosition = Tween<double>( | |
| begin: 800, | |
| end: 550, | |
| ).animate(_controller); | |
| void _onCenterIconTap() { | |
| _controller.isCompleted ? _controller.reverse() : _controller.forward(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| backgroundColor: Colors.black, | |
| body: SafeArea( | |
| child: SizedBox.expand( | |
| child: AnimatedBuilder( | |
| animation: _controller, | |
| builder: (context, child) { | |
| return Stack( | |
| children: [ | |
| child!, | |
| BottomBarActionMenuRow( | |
| topPosition: _bottomBarActionMenuTopPosition.value, | |
| controller: _controller, | |
| ), | |
| Positioned( | |
| bottom: 0, | |
| height: kBottomNavigationBarHeight, | |
| left: 0, | |
| right: 0, | |
| child: PBottomAppBar( | |
| onCenterIconTap: _onCenterIconTap, | |
| rotationAngle: _rotationAngle.value, | |
| centerIconBackgroundColor: | |
| _centerIconBackgroundColor.value, | |
| centerIconForegroundColor: | |
| _centerIconForegroundColor.value, | |
| ), | |
| ), | |
| ], | |
| ); | |
| }, | |
| child: Container( | |
| width: 200.0, | |
| height: 200.0, | |
| color: Colors.green, | |
| child: const Center(child: Text('BODY!')), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| class MenuItem { | |
| final String text; | |
| final IconData icon; | |
| const MenuItem({required this.text, required this.icon}); | |
| } | |
| const List<MenuItem> dataSet = [ | |
| MenuItem(text: 'Add Place', icon: Icons.location_on), | |
| MenuItem(text: 'Create List', icon: Icons.view_list_rounded), | |
| MenuItem(text: 'Add Friend', icon: Icons.person_add_alt_1_rounded) | |
| ]; | |
| class BottomBarActionMenuRow extends StatelessWidget { | |
| final double? topPosition; | |
| final AnimationController controller; | |
| const BottomBarActionMenuRow( | |
| {super.key, this.topPosition, required this.controller}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return Positioned( | |
| height: 180, | |
| top: topPosition, | |
| left: 0, | |
| right: 0, | |
| child: DecoratedBox( | |
| decoration: BoxDecoration( | |
| gradient: LinearGradient( | |
| colors: [ | |
| Colors.white, | |
| Colors.white.withOpacity(0.8), | |
| Colors.white.withOpacity(0.5), | |
| Colors.white.withOpacity(0.35), | |
| Colors.white.withOpacity(0.005), | |
| ], | |
| begin: Alignment.bottomCenter, | |
| end: Alignment.topCenter, | |
| stops: [0.55, 0.65, 0.75, 0.85, 0.99], | |
| ), | |
| ), | |
| child: Row( | |
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
| children: dataSet.map((item) { | |
| int index = dataSet.indexOf(item); | |
| return SlideTransition( | |
| position: Tween<Offset>( | |
| begin: Offset(0, 1.0 + (2 * index)), | |
| end: Offset.zero, | |
| ).animate(controller), | |
| child: PIconButton(item: item), | |
| ); | |
| }).toList(), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| class PIconButton extends StatelessWidget { | |
| final MenuItem item; | |
| const PIconButton({super.key, required this.item}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return Column( | |
| mainAxisSize: MainAxisSize.min, | |
| children: [ | |
| Container( | |
| width: 50, | |
| height: 50, | |
| decoration: const BoxDecoration( | |
| color: Colors.black, | |
| shape: BoxShape.circle, | |
| ), | |
| child: Center( | |
| child: Icon(item.icon, color: Colors.white, size: 24), | |
| ), | |
| ), | |
| const SizedBox(height: 4), | |
| Text( | |
| item.text.toUpperCase(), | |
| style: const TextStyle( | |
| fontSize: 10, | |
| fontWeight: FontWeight.bold, | |
| color: Colors.black, | |
| ), | |
| textAlign: TextAlign.center, | |
| ), | |
| ], | |
| ); | |
| } | |
| } | |
| class PBottomAppBar extends StatelessWidget { | |
| final VoidCallback onCenterIconTap; | |
| final double rotationAngle; | |
| final Color? centerIconBackgroundColor, centerIconForegroundColor; | |
| const PBottomAppBar({ | |
| super.key, | |
| required this.onCenterIconTap, | |
| required this.rotationAngle, | |
| this.centerIconBackgroundColor, | |
| this.centerIconForegroundColor, | |
| }); | |
| @override | |
| Widget build(BuildContext context) { | |
| return Container( | |
| color: Theme.of(context).bottomAppBarTheme.color ?? Colors.white, | |
| child: Row( | |
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
| children: [ | |
| const Icon(Icons.assistant_navigation, | |
| color: Colors.black, size: 30.0), | |
| const Icon(Icons.map_outlined, color: Colors.black, size: 30.0), | |
| Align( | |
| alignment: const Alignment(0, 2), | |
| child: InkWell( | |
| onTap: onCenterIconTap, | |
| child: Transform.rotate( | |
| angle: rotationAngle, | |
| child: Container( | |
| width: 50.0, | |
| height: 50.0, | |
| decoration: BoxDecoration( | |
| color: centerIconBackgroundColor, | |
| shape: BoxShape.circle, | |
| ), | |
| child: Icon(Icons.add, | |
| color: centerIconForegroundColor, size: 30.0), | |
| ), | |
| ), | |
| ), | |
| ), | |
| const Icon(Icons.notifications_outlined, | |
| color: Colors.black, size: 30.0), | |
| const Icon(Icons.person_outline_rounded, | |
| color: Colors.black, size: 30.0), | |
| ], | |
| ), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment