Skip to content

Instantly share code, notes, and snippets.

@edbond
Created April 16, 2020 08:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edbond/7fbad05870cf68ae0354e6df33f53bfd to your computer and use it in GitHub Desktop.
Save edbond/7fbad05870cf68ae0354e6df33f53bfd to your computer and use it in GitHub Desktop.
Flutter Drawer
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class TransitionDrawer extends StatefulWidget {
final Widget child;
final StreamController<void> toggleStream;
TransitionDrawer({
@required this.child,
@required this.toggleStream,
});
@override
_TransitionDrawerState createState() => _TransitionDrawerState();
}
enum DrawerState { Opened, Closed }
enum OnRelease { toLeft, toRight }
class _TransitionDrawerState extends State<TransitionDrawer>
with TickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
OnRelease onRelease = OnRelease.toLeft;
bool trackHorizontalDrag = false;
DrawerState _drawerState = DrawerState.Closed;
double dragOffset;
@override
void initState() {
super.initState();
controller = AnimationController(
lowerBound: 0,
upperBound: 1,
duration: const Duration(milliseconds: 200),
vsync: this,
);
animation = Tween<double>(begin: 0, end: 100).animate(controller)
..addStatusListener((status) {
// print("status ${status}");
if (status == AnimationStatus.completed) {
_drawerState = DrawerState.Opened;
onRelease = OnRelease.toRight;
}
if (status == AnimationStatus.dismissed) {
_drawerState = DrawerState.Closed;
onRelease = OnRelease.toLeft;
}
});
widget.toggleStream.stream.listen((event) {
// print("animating? ${controller.isAnimating}, drawer state=$_drawerState");
if (controller.isAnimating) {
return;
}
if (_drawerState == DrawerState.Closed) {
controller.forward();
} else {
controller.reverse();
}
});
}
@override
void dispose() {
super.dispose();
controller.dispose();
}
@override
Widget build(BuildContext context) {
var width = MediaQuery.of(context).size.width;
return Stack(
children: [
Container(
color: Colors.blue,
child: ListView(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Login",
style: GoogleFonts.robotoMono(),
),
),
),
],
),
),
GestureDetector(
onHorizontalDragStart: (details) {
var progress = animation.value;
var leftX = (width * 0.85) * (progress / 100.0);
var x = details.globalPosition.dx;
dragOffset = x - leftX;
// print(
// "start drag! $x, width=$width, progress=$progress, (width*0.8)*progress=$leftX, $dragDelta");
if (_drawerState == DrawerState.Opened) {
trackHorizontalDrag = true;
return;
}
if (details.globalPosition.dx < width * 0.15) {
trackHorizontalDrag = true;
} else {
trackHorizontalDrag = false;
}
},
onHorizontalDragUpdate: (details) {
if (!trackHorizontalDrag) return;
var x = details.globalPosition.dx;
controller.value = (x - dragOffset) / (width * 0.85);
if (x < width / 2) {
onRelease = OnRelease.toLeft;
} else {
onRelease = OnRelease.toRight;
}
},
onHorizontalDragEnd: (details) {
if (onRelease == OnRelease.toLeft) {
controller.reverse();
} else {
controller.forward();
}
trackHorizontalDrag = false;
},
child: AnimatedBuilder(
animation: animation,
child: widget.child,
builder: (context, child) {
var scale = (0.85 - 1) / 100 * animation.value + 1;
var translateX = (animation.value / 100 * width * 0.85);
return Transform(
alignment: Alignment.centerLeft,
transform: Matrix4.identity()
..translate(translateX, 0)
..scale(scale),
child: child,
);
},
),
),
Positioned(
left: (width * 0.15),
top: 0,
width: 1,
bottom: 0,
child: Container(
color: Colors.redAccent,
),
)
],
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment