Last active
January 29, 2024 11:52
-
-
Save fabiancrx/1be96fd05e3e23c095060f70fa6dedb7 to your computer and use it in GitHub Desktop.
Draggable resizable sheet
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 MaterialApp(home: MyHomePage())); | |
} | |
class MyHomePage extends StatelessWidget { | |
const MyHomePage({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(), | |
body: Center( | |
child: FilledButton( | |
onPressed: () { | |
showDraggableResizableSheet( | |
keyboardDismissedSize: .54, | |
context: context, | |
builder: (_, controller) { | |
return ListView.separated( | |
controller: controller, | |
itemCount: 8, | |
itemBuilder: (context, index) => const TextField(), | |
separatorBuilder: (context, index) => const SizedBox.square(dimension: 16), | |
); | |
}); | |
}, | |
child: const Text('show modal'))), | |
); | |
} | |
} | |
/// Shows a [DraggableScrollableSheet] with [builder] as content. | |
/// The scrollController passed to the builder MUST be assigned to the scrollable eg: listview. | |
/// It automatically expands and contracts when the keyboard is shown/dismissed. | |
Future<void> showDraggableResizableSheet<T>( | |
{required BuildContext context, | |
required ScrollableWidgetBuilder builder, | |
double initialChildSize = .5, | |
double minChildSize = .3, | |
double maxChildSize = 1, | |
bool shrinkOnKeyboardDismissal = true, | |
double keyboardDismissedSize = .8}) async { | |
final sheetController = DraggableScrollableController(); | |
var lastFrameKeyboardShown = false; | |
return showModalBottomSheet<T>( | |
showDragHandle: true, | |
isScrollControlled: true, | |
context: context, | |
builder: (_) => DraggableScrollableSheet( | |
initialChildSize: initialChildSize, | |
minChildSize: minChildSize, | |
maxChildSize: maxChildSize, | |
expand: false, | |
controller: sheetController, | |
builder: (BuildContext context, ScrollController scrollController) { | |
if (context.isKeyboardVisible) { | |
sheetController.animateTo(1, duration: const Duration(milliseconds: 150), curve: Curves.easeInOut); | |
lastFrameKeyboardShown = true; | |
} else if (shrinkOnKeyboardDismissal && !context.isKeyboardVisible && lastFrameKeyboardShown) { | |
sheetController.animateTo(keyboardDismissedSize, | |
duration: const Duration(milliseconds: 450), curve: Curves.easeInOut); | |
lastFrameKeyboardShown = false; | |
} | |
return Scaffold( | |
backgroundColor: Colors.transparent, | |
resizeToAvoidBottomInset: true, | |
body: builder(context, scrollController), | |
); | |
}), | |
).then((value) { | |
sheetController.dispose(); | |
}); | |
} | |
extension ScreenSizeX on BuildContext { | |
/// True If the keyboard is visible in the screen | |
bool get isKeyboardVisible => MediaQuery.of(this).viewInsets.bottom > 100; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment