Flutter - How to set showModalBottomSheet to full height but below status bar? - flutter

I am able to make bottomSheet to full height by using showModalBottomSheet(...) and set the property isScrollControlled:true.
However, the bottom sheet is over the status bar, and that is not what I expect.
Is it possible to make it below the status bar?

as an option you can modify bottom sheet
1. create new file custom_bottom_sheet.dart
2. copy-paste all code from bottom_sheet class into your custom class
3. modify buildPage() method like this
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
Widget bottomSheet = SafeArea(
child: _ModalBottomSheet<T>(
route: this,
backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
shape: shape,
clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled,
enableDrag: enableDrag,
),
);
if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet);
return bottomSheet;
}
use your class
import 'package:flutter/material.dart';
import 'custom_bottom_sheet.dart' as bs;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(child: Page()),
),
);
}
}
class Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('show'),
onPressed: () {
bs.showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => Container(color: Colors.red),
);
},
),
);
}
}
here is modified bottom_sheet class https://pastebin.com/5U7fsqCw
also I think you need to add property
barrierColor: Colors.white.withOpacity(0),
to prevent status bar dimming

No need to create a new class. Simply assign a variable to the padding on the build of your view and use it when opening the dialog.
class MyHomeScreenState extends State<MyHomeScreen> {
double? topPadding;
#override
Widget build(BuildContext context) {
topPadding = MediaQuery.of(context).padding.top;
//...
}
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height -
topPadding!,
color: Colors.green,
);
});
If you look at SafeArea source code this is exactly what is happening. Make sure that your build is at a 'root' level on the widget tree since descendant widgets might not have a top padding because they are not underneath the edges.

Since 20 Jul 2022, you can set useSafeArea parameter to true to show modal under status bar, you can find details here.
showModalBottomSheet<void>(
useSafeArea: true, // <<<<< use this
// ....
);
Note: Now it available on master channel only, and later will be
available on stable channel.

Another easy workaround with rounded borders
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.965,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(16.0),
topRight: const Radius.circular(16.0),
),
),
child: Center(
child: Text("Your content goes here"),
),
),
);

I think this solution is the most suitable for now: (use FractionallySizedBox)
showModalBottomSheet(
context: context,
enableDrag: true,
isScrollControlled: true,
builder: (context) => FractionallySizedBox(
heightFactor: 0.9,
child: Container()
)
);

You can use the constraints parameter and set the height you want
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(35),
topRight: Radius.circular(35),
),
),
constraints: BoxConstraints(maxHeight:
MediaQuery.of(context).size.height - 50),
builder: (context) {
//continue coding..
}

The best and the easiest way is to subtract the total height of device from status bar height. You can get statusBarHeight by MediaQuery.of(context).viewPadding.top and whole device height by MediaQuery.of(context).size.height

Just like #Roddy R's answer but a little simpler
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
builder: (ctx) => Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
child: YourCustomBottomSheet(),
),
),
Thanks Roddy!

Related

How to make showModalBottomSheet responsive in flutter?

I'am trying to show webView in a showModalBottomSheet, using inAppWebView plugin for webView. So when the webView state changes bottomSheet should adjust its height. Currently I just made a hotFix by giving scroll to bottomSheet.
return return showModalBottomSheet(
enableDrag: false,
isDismissible: false,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20.r),
topLeft: Radius.circular(20.r),
),
),
context: context,
builder: (context) => BottomSheet(),
);
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height - (kToolbarHeight * 2),
decoration: BoxDecoration(
color: lmWhite,
borderRadius: BorderRadius.circular(20.r),
),
clipBehavior: Clip.hardEdge,
child: Stack(
children: [
InAppWebView(),
Opacity(),
],
),
);
}
Default height for bottomSheet is half the screenSize
If you want your bottomSheet to Expand according to your content use below code
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[...]
)
}
)
This will automatically expand the bottomSheet according to content inside.

Safearea not working in showModalBottomSheet

Safearea() does not wrap the showModalBottomSheet properly. I need to show the modal under the status bar.
class ModalBottomSheet {
static void renderModalBottomSheet(BuildContext context, Widget widget) {
showModalBottomSheet(
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(border2),
),
),
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: widget,
),
);
},
);
}
}
I have tried the following solutions but it still doesn't work properly
MediaQuery.of(context).padding.top
MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top
Update:
I managed to solve it this way.
add this to the bottomsheet
backgroundColor: Colors.transparent,
and padding top
top: MediaQuery.of(context).padding.top,
full code:
class ModalBottomSheet {
static void renderModalBottomSheet(BuildContext context, Widget widget) {
showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.transparent,
context: context,
builder: (_) {
return SafeArea(
child: Padding(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: widget,
),
);
},
);
}
}
your child widget can have the border radius and colors instead.
open keyboard
closed keyboard
Try this. If it doesn't work, refer this page
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[...
you should get MediaQuery.of(context).viewPadding.top before showModalBottomSheet and pass it to sheet inside, then use EdgeInsets.top inside the sheet.

barrierDismissible in showGeneralDialog is not working with Scaffold

I am still new with Flutter. I try to make my dialog to be able to dismiss when click outside of the dialog. However if i use Scaffold, the barrierDismissible:true is not working. I tried to use Wrap but an error : No Material widget found will be displayed. Is there any idea on how to dismiss the dialog?
This is my code:
showGeneralDialog(
barrierDismissible: true,
pageBuilder: (context, anim1, anim2) {
context1 = context;
return StatefulBuilder(
builder: (context, setState) {
return Scaffold(
backgroundColor: Colors.black .withOpacity(0.0),
body: Align(
alignment: Alignment.bottomCenter,
child: Container(
child: InkWell()
)
)
}
}
)
Scaffold is not required to display showGeneralDialog. The Material widget was required in your code because the InkWell widget needs a Material ancestor. You could use any widget that provides material such as Card or Material widget itself. Also barrierLabel cannot be null.
Please see the working code below or you can directly run the code on Dartpad https://dartpad.dev/6c047a6cabec9bbd00a048c972098671
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text("showGeneralDialog Demo"),
),
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierColor: Colors.black54,
pageBuilder: (context, anim1, anim2) {
return Center(
child: Container(
width: 200,
height: 100,
child: StatefulBuilder(
builder: (context, snapshot) {
return const Card(
color: Colors.white,
child: Center(
child: InkWell(
child: Text(
"Press outside to close",
style: TextStyle(color: Colors.black),
),
),
),
);
},
),
),
);
},
);
},
child: const Text("Show Dialog"));
}
}
For anyone who needs to use a Scaffold in their AlertDialogs (perhaps to use ScaffoldMessenger), here is the simple work around:
Wrap the Scaffold with an IgnorePointer. The "barrierDismissible" value will now work.
#override
Widget build(BuildContext context) {
return IgnorePointer(
child: Scaffold(
backgroundColor: Colors.transparent,
body: AlertDialog(
title: title,
content: SizedBox(
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: ListBody(
children: content
),
),
),
actions: actions,
insetPadding: const EdgeInsets.all(24.0),
shape: Theme.of(context).dialogTheme.shape,
backgroundColor: Theme.of(context).dialogTheme.backgroundColor,
)
),
);
}
Add this in showGeneralDialog
barrierLabel: ""
Code will look like this
showGeneralDialog(
barrierDismissible: true,
barrierLabel: "",
pageBuilder: (context, anim1, anim2) {
context1 = context;
return StatefulBuilder(
builder: (context, setState) {
return Scaffold(
backgroundColor: Colors.black .withOpacity(0.0),
body: Align(
alignment: Alignment.bottomCenter,
child: Container(
child: InkWell()
)
)
}
}
)
I was encountering this issue when using showGeneralDialog on top of a map view. The root cause of my issue was that I had wrapped the dialog in a PointerInterceptor.
To fix it, I had to set intercepting to false.
PointerInterceptor(
intercepting: onMap, // false when not an map
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
)
)

showModalBottomSheet and Border Radius

I want to make a showModalBottomSheet with a container in Flutter. I want this container to have rounded the top borders but, when I tried this, there are a few small uncolored spaces in the corners. How can I delete them?
This is the code I used:
class OverlayWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.80,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
),
child: Center(...),
);
},
);
},
);
}
}
The resultant widget is the following:
I want to delete the white spaces in the top border.
Thank you in advance
Reviewing the documentation I realize that the showModalBottomSheet function has a property called 'backgroundColor' 🤦‍♀️
Just adding:
backgroundColor: Colors.transparent,
to the showModalBottomSheet it works.
Thanks for the help anyway!
ThemeData has bottomSheetTheme parameter, you can override this as following :
MaterialApp(
...
theme: ThemeData(
...
bottomSheetTheme:
BottomSheetThemeData(backgroundColor: Colors.transparent),
),
...
),
This will give transparent color for the bottomSheet

How to make sort slide down window?

I try to make something like this, or this
I use
IconButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) => MyPopup()));
},
to call for it, but in popup what kind of widget should return and and how to animate its appearance by pushing it from the bottom and closing it using swipe down?
You can use the bottom sheet from the Material design component which is same as this,
Guidline or example from Material Design site
Also class from official flutter doc.
Example:
void _showBottomSheet(){
showModalBottomSheet(
context: context,
builder: (builder){
return new Container(
height: 350.0,
color: Colors.transparent, //could change this to Color(0xFF737373),
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(15.0),
topRight: const Radius.circular(15.0))),
child: new Center(
child: new Text("Model Sheet Example Demo"),
)),
);
}
);
}