Last active
April 5, 2021 23:03
-
-
Save kranfix/e561d15dde81e9f73e2689d568314775 to your computer and use it in GitHub Desktop.
An animated drawer with rotated body based on https://www.youtube.com/watch?v=ZHRhSFXqHJY
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
// based on: https://www.youtube.com/watch?v=ZHRhSFXqHJY | |
// but better modularied | |
import 'dart:math'; | |
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData(), | |
debugShowCheckedModeBanner: false, | |
home: Scaffold( | |
body: Center( | |
child: MyWidget(), | |
), | |
), | |
); | |
} | |
} | |
class MyWidget extends StatefulWidget { | |
const MyWidget(); | |
@override | |
_MyWidgetState createState() => _MyWidgetState(); | |
} | |
class _MyWidgetState extends State<MyWidget> { | |
var value = 0.0; | |
void toggle() { | |
setState(() => value = 1 - value); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return GestureDetector( | |
onHorizontalDragUpdate: (e){ | |
if( | |
(e.delta.dx > 30 && value == 0.0) | |
|| (e.delta.dx < -30 && value == 1.0) | |
) { | |
toggle(); | |
} | |
}, | |
child: Stack( | |
children: [ | |
Menu( | |
avatarUrl: | |
'https://avatars.githubusercontent.com/u/1251381?s=460&v=4', | |
username: 'Frank Moreno', | |
children: [ | |
MenuTile( | |
icon: Icons.home, | |
text: Text('Home'), | |
), | |
MenuTile( | |
icon: Icons.person, | |
text: Text('Profile'), | |
), | |
MenuTile( | |
icon: Icons.settings, | |
text: Text('Settings'), | |
), | |
MenuTile( | |
icon: Icons.logout, | |
text: Text('Log out'), | |
), | |
], | |
), | |
TweenAnimationBuilder( | |
tween: Tween<double>(begin: 1 - value, end: value), | |
duration: Duration(milliseconds: 300), | |
builder: (_, double val, __) { | |
return Transform( | |
alignment: Alignment.center, | |
transform: Matrix4.identity() | |
..setEntry(3, 2, 0.001) | |
..setEntry(0, 3, 200 * val) | |
..rotateY(pi / 6 * val), | |
child: AppBody(), | |
); | |
}, | |
), | |
], | |
), | |
); | |
} | |
} | |
class AppBody extends StatelessWidget { | |
const AppBody({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text('Animatied Drawer'), | |
), | |
body: Center(child: Text('Hello Flutter Hispano')), | |
); | |
} | |
} | |
class Menu extends StatelessWidget { | |
const Menu({ | |
Key? key, | |
required this.children, | |
required this.avatarUrl, | |
required this.username, | |
}) : super(key: key); | |
final String avatarUrl; | |
final String username; | |
final List<Widget> children; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
width: double.infinity, | |
decoration: BoxDecoration( | |
gradient: LinearGradient( | |
colors: [ | |
Colors.orange.shade400, | |
Colors.orange.shade800, | |
Colors.orange.shade900, | |
], | |
begin: Alignment.bottomCenter, | |
end: Alignment.topCenter, | |
), | |
), | |
child: SafeArea( | |
child: Container( | |
width: 200, | |
padding: EdgeInsets.all(8.0), | |
alignment: Alignment.topLeft, | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
DrawerHeader( | |
child: Padding( | |
padding: EdgeInsets.only(left: 40), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: [ | |
CircleAvatar( | |
radius: 50.0, | |
backgroundImage: NetworkImage(avatarUrl), | |
), | |
SizedBox(height: 10), | |
Text( | |
username, | |
style: TextStyle( | |
color: Colors.white, | |
fontSize: 20, | |
), | |
), | |
], | |
), | |
), | |
), | |
Expanded( | |
child: ListView( | |
padding: EdgeInsets.zero, | |
children: children, | |
), | |
), | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
class MenuTile extends StatelessWidget { | |
const MenuTile({ | |
Key? key, | |
this.onTap, | |
required this.icon, | |
required this.text, | |
}) : super(key: key); | |
final VoidCallback? onTap; | |
final IconData icon; | |
final Widget text; | |
@override | |
Widget build(BuildContext context) { | |
return ListTile( | |
onTap: onTap, | |
leading: Icon( | |
icon, | |
color: Colors.white, | |
), | |
title: DefaultTextStyle( | |
style: TextStyle(color: Colors.white), | |
child: text, | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment