Flutter BottomSheet change width

3,234

Solution 1

UPDATE : Flutter now support constraints property in showModalBottomSheet

showModalBottomSheet(
  context: context,
  constraints: BoxConstraints(
     maxWidth: Responsive.isMobile(context) ? Get.width : 600,              
  ),
  builder: ...
),

Solution 2

UPDATE

Flutter added constraints to showModalBottomSheet and it's available on master, dev and beta :)

Solution 3

You can wrap your widget with an Align widget and set the alignment to bottom center, then you can set box constraints if you want to have a maximum width

Align(
  alignment: Alignment.bottomCenter,
  child: ConstrainedBox(
    constraints: BoxConstraints(...),
    child: ...
  ),
)
Share:
3,234
Dennis Barzanoff
Author by

Dennis Barzanoff

Updated on December 01, 2022

Comments

  • Dennis Barzanoff
    Dennis Barzanoff over 1 year

    I want the bottom sheet to look like the one in Angular Material.
    enter image description here The sheet instead expands to the maximum width. The problem is that I cannot configure the width of the bottom sheet. It currently looks like thisenter image description here

    My code looks like this:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: ...,
            floatingActionButton: FloatingActionButton(
              child: Icon(Icons.add),
              tooltip: 'Add File',
              onPressed: () => showModalBottomSheet(
                context: context,
                builder: (context) => AddFileBottomSheet(),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(10),
                    topRight: Radius.circular(10),
                  ),
                ),
                // backgroundColor: Colors.transparent,
                isScrollControlled: true,
              ),
            ),
          ),
        );
      }
    }
    
    class AddFileBottomSheet extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Container(
                padding: EdgeInsets.symmetric(vertical: 20, horizontal: 5),
                alignment: Alignment.center,
                child: Text(
                  'Create New File',
                  style: Theme.of(context).textTheme.headline5,
                ),
              ),
              GridView.count(
                shrinkWrap: true,
                crossAxisCount: 3,
                children: [
                  _gridTile(
                    context: context,
                    icon: Icon(Icons.file_upload),
                    text: 'Upload File',
                    callback: () => print('lel'),
                  ),
                  _gridTile(
                    context: context,
                    icon: Icon(Icons.create),
                    text: 'Create Text File',
                    callback: () => print('lel'),
                  ),
                ],
              ),
            ],
        );
      }
    
      Widget _gridTile({
        @required BuildContext context,
        @required Icon icon,
        @required String text,
        @required void callback(),
      }) {
        return InkWell(
            onTap: () => callback(),
            child: Container(
              padding: EdgeInsets.all(15),
              alignment: Alignment.center,
              height: double.infinity,
              width: double.infinity,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  icon,
                  Text(text, style: Theme.of(context).textTheme.subtitle2),
                ],
              ),
            ),
        );
      }
    }
    
    

    I know I can fake it having a smaller width when making some of it transparent, but I have round edges and they won't get preserved.

    Workaround #1

    I managed to do it by changing the canvasColor to transparent and making the borders rounded in the widget: enter image description here This way, however I need to do additional logic to dismiss it when the user clicks the fake transparent area.

    First add the canvasColor to the context somehow:

    ...
          floatingActionButton: Theme(
            data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
            child: Builder(
              builder: (context) => FloatingActionButton(
                child: Icon(Icons.add),
                tooltip: 'Add File',
                onPressed: () => showModalBottomSheet(
                  context: context,
                  builder: (context) => AddFileBottomSheet(),
                  // shape: RoundedRectangleBorder(
                  //   borderRadius: BorderRadius.only(
                  //     topLeft: Radius.circular(10),
                  //     topRight: Radius.circular(10),
                  //   ),
                  // ),
                  // backgroundColor: Colors.transparent,
                  isScrollControlled: true,
                ),
              ),
            ),
          ),
    ...
    

    Then fake the width

        return Container(
          padding: EdgeInsets.symmetric(horizontal: 300),
          child: Container(
            decoration: BoxDecoration(
              color: Colors.white,
              shape: BoxShape.rectangle,
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(10),
                topRight: Radius.circular(10),
              ),
            ),
            // backgroundColor: Colors.transparent,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Container(
                  padding: EdgeInsets.symmetric(vertical: 20, horizontal: 5),
                  alignment: Alignment.center,
                  child: Text(
                    'Create New File',
                    style: Theme.of(context).textTheme.headline5,
                  ),
                ),
                GridView.count(
                  shrinkWrap: true,
                  crossAxisCount: 3,
                  children: [
                    _gridTile(
                      context: context,
                      icon: Icon(Icons.file_upload),
                      text: 'Upload File',
                      callback: () => print('lel'),
                    ),
                    _gridTile(
                      context: context,
                      icon: Icon(Icons.create),
                      text: 'Create Text File',
                      callback: () => print('lel'),
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
    

    I wonder if there is a standard approach to this and I need your help. I tried making a DartPad example, but it gives me Script error.

    My idea was to try and make it mobile friendly with something like this:

        final isMobile = MediaQuery.of(context).size.width < 700;
        return Container(
          padding: EdgeInsets.symmetric(horizontal: isMobile ? 0: 300),
          child: ...
        )
    

    This will make it full-width when mobile and with some padding when desktop.

    • James Poulose
      James Poulose about 2 years
      As of now adding a constraint to showModalBottomSheet is the right way to go.
  • Dennis Barzanoff
    Dennis Barzanoff over 3 years
    looks promising, but I cannot test it rn. I will accept your answer if you are sure it works
  • Pantelis Tsak
    Pantelis Tsak over 3 years
    Yeah, I had the same problem as you, as I wanted not to have full width bottom sheet on tablets. You can try it your self some day, thanks
  • Rebar
    Rebar almost 3 years
    This solution is not working. I've created a feature request on Flutter repo. Hope for the best.