Skip to content

Instantly share code, notes, and snippets.

@crimsonsuv
Created November 29, 2018 07:02
Show Gist options
  • Select an option

  • Save crimsonsuv/b25d5ebd04236f9be2aa66accba19446 to your computer and use it in GitHub Desktop.

Select an option

Save crimsonsuv/b25d5ebd04236f9be2aa66accba19446 to your computer and use it in GitHub Desktop.
Flutter Modal bottom sheet whith input fix and full screen sheet
//Flutter Modal Bottom Sheet
//Modified by Suvadeep Das
//Based on https://gist.github.com/andrelsmoraes/9e4af0133bff8960c1feeb0ead7fd749
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
const Duration _kBottomSheetDuration = const Duration(milliseconds: 200);
class _ModalBottomSheetLayout extends SingleChildLayoutDelegate {
_ModalBottomSheetLayout(this.progress, this.bottomInset);
final double progress;
final double bottomInset;
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return new BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: 0.0,
maxHeight: constraints.maxHeight
);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
return new Offset(0.0, size.height - bottomInset - childSize.height * progress);
}
@override
bool shouldRelayout(_ModalBottomSheetLayout oldDelegate) {
return progress != oldDelegate.progress || bottomInset != oldDelegate.bottomInset;
}
}
class _ModalBottomSheet<T> extends StatefulWidget {
const _ModalBottomSheet({ Key key, this.route }) : super(key: key);
final _ModalBottomSheetRoute<T> route;
@override
_ModalBottomSheetState<T> createState() => new _ModalBottomSheetState<T>();
}
class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
@override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: widget.route.dismissOnTap ? () => Navigator.pop(context) : null,
child: new AnimatedBuilder(
animation: widget.route.animation,
builder: (BuildContext context, Widget child) {
double bottomInset = widget.route.resizeToAvoidBottomPadding
? MediaQuery.of(context).viewInsets.bottom : 0.0;
return new ClipRect(
child: new CustomSingleChildLayout(
delegate: new _ModalBottomSheetLayout(widget.route.animation.value, bottomInset),
child: new BottomSheet(
animationController: widget.route._animationController,
onClosing: () => Navigator.pop(context),
builder: widget.route.builder
)
)
);
}
)
);
}
}
class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
_ModalBottomSheetRoute({
this.builder,
this.theme,
this.barrierLabel,
RouteSettings settings,
this.resizeToAvoidBottomPadding,
this.dismissOnTap,
}) : super(settings: settings);
final WidgetBuilder builder;
final ThemeData theme;
final bool resizeToAvoidBottomPadding;
final bool dismissOnTap;
@override
Duration get transitionDuration => _kBottomSheetDuration;
@override
bool get barrierDismissible => false;
@override
final String barrierLabel;
@override
Color get barrierColor => Colors.black54;
AnimationController _animationController;
@override
AnimationController createAnimationController() {
assert(_animationController == null);
_animationController = BottomSheet.createAnimationController(navigator.overlay);
return _animationController;
}
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
// By definition, the bottom sheet is aligned to the bottom of the page
// and isn't exposed to the top padding of the MediaQuery.
Widget bottomSheet = new MediaQuery.removePadding(
context: context,
removeTop: true,
child: new _ModalBottomSheet<T>(route: this),
);
if (theme != null)
bottomSheet = new Theme(data: theme, child: bottomSheet);
return bottomSheet;
}
}
/// Shows a modal material design bottom sheet.
///
/// A modal bottom sheet is an alternative to a menu or a dialog and prevents
/// the user from interacting with the rest of the app.
///
/// A closely related widget is a persistent bottom sheet, which shows
/// information that supplements the primary content of the app without
/// preventing the use from interacting with the app. Persistent bottom sheets
/// can be created and displayed with the [showBottomSheet] function or the
/// [ScaffoldState.showBottomSheet] method.
///
/// The `context` argument is used to look up the [Navigator] and [Theme] for
/// the bottom sheet. It is only used when the method is called. Its
/// corresponding widget can be safely removed from the tree before the bottom
/// sheet is closed.
///
/// Returns a `Future` that resolves to the value (if any) that was passed to
/// [Navigator.pop] when the modal bottom sheet was closed.
///
/// See also:
///
/// * [BottomSheet], which is the widget normally returned by the function
/// passed as the `builder` argument to [showModalBottomSheet].
/// * [showBottomSheet] and [ScaffoldState.showBottomSheet], for showing
/// non-modal bottom sheets.
/// * <https://material.google.com/components/bottom-sheets.html#bottom-sheets-modal-bottom-sheets>
Future<T> showModalBottomSheetApp<T>({
@required BuildContext context,
@required WidgetBuilder builder,
bool dismissOnTap: false,
bool resizeToAvoidBottomPadding : true,
}) {
assert(context != null);
assert(builder != null);
return Navigator.push(context, new _ModalBottomSheetRoute<T>(
builder: builder,
theme: Theme.of(context, shadowThemeOnly: true),
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
dismissOnTap: dismissOnTap,
));
}
@crimsonsuv
Copy link
Copy Markdown
Author

Just drag this file to your project and when calling Modal Bottom sheet use it as follows
void _showSignupModalSheet() { showModalBottomSheetApp( context: context, builder: (builder) { return new SignupScreen(); }); }

If you dont want full screen sheet then you can modify
BoxConstraints getConstraintsForChild(BoxConstraints constraints) { return new BoxConstraints( minWidth: constraints.maxWidth, maxWidth: constraints.maxWidth, minHeight: 0.0, maxHeight: constraints.maxHeight ); }

and change maxHeight to default:
maxHeight: constraints.maxHeight * 9.0 / 16.0

### here is the usage sample:
Calling the modal bottom sheet
void _showSignupModalSheet() { showModalBottomSheetApp( context: context, builder: (builder) { return new buildSheetLogin(context); }); }

Declaring bottom sheet
Widget buildSheetLogin(BuildContext context) { return new Container( ....... ); }

@ErraticFox
Copy link
Copy Markdown

ErraticFox commented Dec 8, 2018

Just drag this file to your project and when calling Modal Bottom sheet use it as follows
void _showSignupModalSheet() { showModalBottomSheetApp( context: context, builder: (builder) { return new SignupScreen(); }); }

Can you tell us where to "just drag this file" and if we need to import it? This helps out us new people quite a bit. :^)

In example if I have this block of code, how do I implement something like that?

void _addFundBottomSheet(context) {
  showModalBottomSheet(
      context: context,
      builder: (BuildContext builder) {
        return Container(
          //bunch of code
          );
      });
}

EDIT: Didn't realize it was showModalBottomSheetApp and not showModalBottomSheet. 😄

@betapcode
Copy link
Copy Markdown

Great, you know exactly what i need to do !

@QSKOBE24
Copy link
Copy Markdown

Great Thanks

@ariefannur
Copy link
Copy Markdown

Great Work as well

@andreagr
Copy link
Copy Markdown

Great work

@jaceshim
Copy link
Copy Markdown

jaceshim commented Feb 23, 2019

Great Work!
Works fine! Thank you.

@qxwei
Copy link
Copy Markdown

qxwei commented Apr 2, 2019

Great work ,thank you

@mmustafasesudia
Copy link
Copy Markdown

Work like champ..!
Thank you.

@GiorgioBertolotti
Copy link
Copy Markdown

It works great, thanks!
I've just added a few lines to adjust the height to stay below the statusBar...

@vishalinfant
Copy link
Copy Markdown

Wonderful...Awesome....Marvellous....Saved my time....Good day.....

@rubann7
Copy link
Copy Markdown

rubann7 commented Jun 15, 2019

Great Work Dude !!

@crimsonsuv
Copy link
Copy Markdown
Author

Thanks guys, I have many other ready to use things also but I though no one reads or needs it but after seeing the comments I guess it will be good Idea to put those as well..

@pookzzz
Copy link
Copy Markdown

pookzzz commented Jun 17, 2019

Yea thank you so much for sharing your fix!

@lanrehnics
Copy link
Copy Markdown

Awesome ... Works like charm.

@sidbait
Copy link
Copy Markdown

sidbait commented Jun 26, 2019

It works great, thanks!
I've just added a few lines to adjust the height to stay below the statusBar...

What you have added? Can you please share?

@GiorgioBertolotti
Copy link
Copy Markdown

It works great, thanks!
I've just added a few lines to adjust the height to stay below the statusBar...

What you have added? Can you please share?

Sure, this is the gist. Hope it works for you too! :)

@bennibau
Copy link
Copy Markdown

bennibau commented Jul 5, 2019

great work

@semutnest
Copy link
Copy Markdown

@idrisAkbarA
Copy link
Copy Markdown

great, thank you so much. but it doesn't close the bottom sheet when the grayed area touched. maybe is there any way to bring this feature back?

@muellercornelius
Copy link
Copy Markdown

@idrisAkbarA Hi Idris ;)
found a very simple solution to close the modal when the gray area is touched.
You only need to set barrierDismissible to true.

@override
  bool get barrierDismissible => false;

-->

@override
  bool get barrierDismissible => true;

Hope it helps ;)

@a0y1a
Copy link
Copy Markdown

a0y1a commented Dec 19, 2019

Great work, thanks

@ermiry
Copy link
Copy Markdown

ermiry commented Jan 9, 2020

Thank you very much, you can also control the height if you put a container with your desired height as a background in the showModalBottomSheetApp ()

@matthewkooshad
Copy link
Copy Markdown

i would like to keep this:
@OverRide
bool get barrierDismissible => false;

but, when the barrier is pressed, i want to do an action with the modal content and then Navigator.pop(context);
how can i achieve that? thanks

@matthewkooshad
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment