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

Viewed 8159

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.

enter image description here

Is it possible to make it below the status bar?

7 Answers

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;
  }
  1. 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.

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"),
    ),
),

);

enter image description 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()
  )
);

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!

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..
      }
Related