Skip to content

Instantly share code, notes, and snippets.

@AlexV525
Last active June 7, 2022 09:29
Show Gist options
  • Save AlexV525/a6f271b1e38793152167b9fccf601949 to your computer and use it in GitHub Desktop.
Save AlexV525/a6f271b1e38793152167b9fccf601949 to your computer and use it in GitHub Desktop.
Drawer in a transparent page route
//
// [Author] Alex (https://github.com/AlexV525)
// [Date] 2022/6/7 16:35
//
import 'package:flutter/material.dart';
/// A wrapped [Drawer] that typically useful when placed in a transparent route.
class CustomDrawer extends StatefulWidget {
const CustomDrawer({
Key? key,
required this.builder,
this.drawerAlignment = DrawerAlignment.start,
this.scrimColor = Colors.transparent,
this.fractionalWidthFactor = 1.0,
this.fractionalHeightFactor = 1.0,
this.fractionalAlignment = AlignmentDirectional.centerStart,
}) : super(key: key);
final WidgetBuilder builder;
final DrawerAlignment drawerAlignment;
final Color scrimColor;
final double fractionalWidthFactor;
final double fractionalHeightFactor;
final AlignmentGeometry fractionalAlignment;
@override
State<CustomDrawer> createState() => _CustomDrawerState();
}
class _CustomDrawerState extends State<CustomDrawer> {
final GlobalKey<DrawerControllerState> _drawerControllerKey = GlobalKey();
final ValueNotifier<int> _pointers = ValueNotifier<int>(0);
final ValueNotifier<bool> _isDrawerOpen = ValueNotifier<bool>(true);
bool _isDrawerClosing = false;
@override
void initState() {
super.initState();
_pointers.addListener(_pointerListener);
}
@override
void dispose() {
_pointers.dispose();
_isDrawerOpen.dispose();
super.dispose();
}
void _pointerListener() {
if (_pointers.value == 0 && _isDrawerClosing) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop();
});
}
}
void _drawerCallback(bool isOpened) {
if (!isOpened && !_isDrawerClosing) {
_isDrawerClosing = true;
if (_pointers.value == 0) {
Navigator.of(context).pop();
}
}
}
Future<bool> _onWillPop() async {
if (!_isDrawerClosing) {
_isDrawerClosing = true;
_drawerControllerKey.currentState?.close();
}
return false;
}
Widget _buildDrawer(BuildContext context, bool isDrawerOpen, Widget? child) {
return DrawerController(
key: _drawerControllerKey,
alignment: widget.drawerAlignment,
enableOpenDragGesture: false,
isDrawerOpen: isDrawerOpen,
drawerCallback: _drawerCallback,
scrimColor: widget.scrimColor,
child: child!,
);
}
@override
Widget build(BuildContext context) {
Widget child = widget.builder(context);
if (widget.fractionalWidthFactor < 1 || widget.fractionalHeightFactor < 1) {
child = FractionallySizedBox(
alignment: widget.fractionalAlignment,
widthFactor: widget.fractionalWidthFactor,
heightFactor: widget.fractionalHeightFactor,
child: child,
);
}
return WillPopScope(
onWillPop: _onWillPop,
child: Listener(
onPointerDown: (_) => _pointers.value++,
onPointerUp: (_) => _pointers.value--,
child: ValueListenableBuilder<bool>(
valueListenable: _isDrawerOpen,
builder: _buildDrawer,
child: child,
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment