Last active
June 7, 2022 09:29
-
-
Save AlexV525/a6f271b1e38793152167b9fccf601949 to your computer and use it in GitHub Desktop.
Drawer in a transparent page route
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
// | |
// [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