100

I'm probably missing something obvious here, but my BottomSheet only takes up the bottom half the screen, even though the widgets in it take up more space. So now there is scrolling behavior inside the BottomSheet. I'd like to be able to increase the BottomSheet so that the user doesn't have to scroll as much.

I also want to add a borderRadius to the top of my BottomSheet, so that it looks more "modal"-y or "tab"-like.

Code:

void _showBottomSheet(BuildContext context) {
    showModalBottomSheet<Null>(
      context: context,
      builder: (BuildContext context) {
        return _bottomSheetScreen; // defined earlier on
      },
    );
}

I've tried:

showModalBottomSheet<Null>(
  context: context,
  builder: (BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: _borderRadius,
      ),
      height: 1000.0,
      child: _bottomSheetScreen,
    );
  },
);

but it seems like that only affects the contents inside the BottomSheet, and does not customize the BottomSheet itself.

Mary
  • 18,347
  • 23
  • 59
  • 76
  • 1
    currently not possible. If you want something custom, use `Navigator` to push a custom modal. There's also a similar issue in github about expanding a bottom sheet : https://github.com/flutter/flutter/issues/497 – Rémi Rousselet Feb 24 '18 at 23:49
  • Good to know, I'll thumb up that issue. Thanks for the suggestion about using a custom modal with Navigator, I hadn't thought of that! – Mary Feb 25 '18 at 00:15

18 Answers18

201

Default height for bottomSheet is half the screenSize

If you want your bottomSheet to EXPAND according to your content DYNAMICALLY

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.

For adding a radius on top of bottomSheet return below code to `bottomSheet'

Container(
  child: Container(
    decoration: new BoxDecoration(
      color: forDialog ? Color(0xFF737373) : Colors.white,
      borderRadius: new BorderRadius.only(
            topLeft: const Radius.circular(25.0),
            topRight: const Radius.circular(25.0))),
      child: yourWidget(),
   ),
)

Complete code meeting both requirements

showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
  return Wrap(
      children: <Widget>[
          Container(
                 child: Container(
                  decoration: new BoxDecoration(
                    color: forDialog ? Color(0xFF737373) : Colors.white,
                    borderRadius: new BorderRadius.only(
                          topLeft: const Radius.circular(25.0),
                          topRight: const Radius.circular(25.0))),
                    child: yourWidget(),
                 ),
              )
      ]
   )
 }
)
Vicky Salunkhe
  • 9,869
  • 6
  • 42
  • 59
  • 3
    if there is a ListView in Wrap,it won't be able to scroll.if I replace Wrap to Column,it will be overflow.why? – parcool Mar 23 '20 at 06:49
  • 1
    @parcool try using `SingleChildScrollView` widget instead of `ListView` widget, that may help you with your query. – Vicky Salunkhe Aug 26 '20 at 13:43
  • @parcool Actually, you just have to wrap your `ListView` around a `Expanded`, because if the `ListView` is a direct child of `Column`, Flutter will fail to infer its size because `ListView` has a variable size depending on its children as well. – Guilherme Matuella Oct 20 '20 at 18:51
  • Great answer, any suggestion for keyboard pushing up the bottom sheet? bottom sheet goes behind keyboard – Arrowsome Nov 21 '20 at 11:39
  • 10
    To add the radius on top I prefer to add it on shape property of the modal. shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(12))), – Pedro Romão Nov 24 '20 at 20:04
  • For borderRadius, one could also use shape attr to reduce the number of widgets... – emanuel sanga Feb 12 '21 at 08:43
  • 1
    @Guilherme Matuella The list does not work in the Expanded layout if the widget is in a column that is under the container which has a root view of WrapWidget. Wrap Widget> Container >Column>Expanded>List View – Ravi Parmar Jun 01 '21 at 19:32
  • 1
    @RaviParmar I'm pretty sure that when you set the `ListView.shrinkWrap` to `true` or inside an `Expanded` (the latter depending on the parent and siblings), it does allow it to be placed pretty much anywhere. Anyways, I just mentioned this to what @parcool mentioned, it was not a suggestion to this answer whatsoever. – Guilherme Matuella Jun 01 '21 at 19:46
  • @VickySalunkhe this is working for me without isScrollControlled: true seemed to be what helped – jchua Oct 21 '21 at 04:02
  • hi @VickySalunkhe! I'm having an issue with this: in release mode bottomSheet is shown expanded with default height instead of wrapping content, moreover content is covered by a rectangle shape that ignores top border radius styles. Nothing strange happens in debug mode – riccardogabellone Feb 05 '22 at 18:29
  • @parcool Have you found the answer? or Is there any other approach? In 2022, still facing same issue, – karthikeyan Jun 10 '22 at 11:37
96

It's possible this way

showModalBottomSheet(
  context: context,
  isScrollControlled: true,
  backgroundColor: Colors.transparent,
  builder: (context) => Container(
    height: MediaQuery.of(context).size.height * 0.75,
    decoration: new BoxDecoration(
      color: Colors.white,
      borderRadius: new BorderRadius.only(
        topLeft: const Radius.circular(25.0),
        topRight: const Radius.circular(25.0),
      ),
    ),
    child: Center(
      child: Text("Modal content goes here"),
    ),
  ),
);
  1. Set isScrollControlled: true and backgroundColor: Colors.transparent for the modal
  2. Provide a Container with required height: as root widget to modal builder
  3. Provide BoxDecoration with required borderRadius for the Container

Sample Screenshot

farhan ali
  • 2,462
  • 1
  • 21
  • 15
26

You can use a Column Inside a SingleChildScrollView to dynamically change the height of bottom sheet and also it gets scrollable once it exceeds the available max height, make sure the isScrollControlled is set to true, And for the border radius the shape property will help you add the borderRadius to the bottomsheet. here's a dartpad example for the same


  Future<void> _showBottomSheet() async {
    return showModalBottomSheet(
      isScrollControlled: true,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(13)),
      backgroundColor: Colors.white,
      context: context,
      builder: (context) => SingleChildScrollView(
          child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: List.generate(kBoxes, (index) => _squareBox(index)))),
    );
  }

Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
23

No need to wrap anything. Only set:

  • isScrollControlled: true in showModalBottomSheet
  • shrinkWrap: true, in ListView

Here is the minimal general code:

import 'package:flutter/material.dart';

Future<Widget> show123(BuildContext context) {
  return showModalBottomSheet<dynamic>(
      useRootNavigator: true,
      isScrollControlled: true,
      context: context,
      builder: (BuildContext bc) {
        return ListView(
          shrinkWrap: true,
          children: [
            ListItem(),
            ListItem(),
            ListItem(),
          ],
        );
      });
}

You can get inspired by my case which depends on the number of AlbumRow dynamically. If the height reaches the maximum, you can get to the bottom by scrolling.

enter image description here enter image description here


import 'package:flutter/material.dart';

Future<Widget> showBottomSheet(BuildContext context) {
  return showModalBottomSheet<dynamic>(
      useRootNavigator: true,
      barrierColor: Colors.black.withOpacity(0.5),
      isScrollControlled: true,
      context: context,
      builder: (BuildContext bc) {
        return ConstrainedBox(
          constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
          child: Container(
            decoration: new BoxDecoration(
                color: Colors.blue, borderRadius: new BorderRadius.only(topLeft: const Radius.circular(25.0), topRight: const Radius.circular(25.0))),
            child: ListView(
              shrinkWrap: true,
              children: [
                Padding(
                  padding: const EdgeInsets.fromLTRB(30, 30, 30, 45),
                  child: Text(
                    'Choose Album',
                    textAlign: TextAlign.center,
                  ),
                ),
                AlbumRow(title: 'For Weekends arta iretnairstnaisetn aistn aisetn'),
                AlbumRow(title: 'Creative'),
                AlbumRow(title: 'Christmas'),
                AlbumRow(title: 'For Weekends arta iretnairstnaisetn aistn aisetn'),
              ],
            ),
          ),
        );
      });
}
Tomas Baran
  • 1,570
  • 2
  • 20
  • 37
13

Use the Code Below

Note : If You are using column then use mainAxisSize: MainAxisSize.min


// make isScrollControlled : true
// if using column then make - mainAxisSize: MainAxisSize.min

showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
  return YourWidget();
 }
)
Jayant Dhingra
  • 526
  • 6
  • 11
12

For changing the height of bottomsheet it's better to use the bottomsheet's constraints and isScrollControlled properties.

Like this:

showModalBottomSheet(
  constraints: BoxConstraints.loose(Size(
            MediaQuery.of(context).size.width,
            MediaQuery.of(context).size.height * 0.75)), // <= this is set to 3/4 of screen size.
  isScrollControlled: true, // <= set to true. setting this without constrains may cause full screen bottomsheet.
  context: context,
  builder: (context) => yourWidget()
);

For border radius use the shape property:

showModalBottomSheet(
  shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.vertical(top: Radius.circular(45))), // <= set preferable radius.
  context: context,
  builder: (context) => yourWidget()
);
Mohamad Bastin
  • 309
  • 2
  • 6
9

Use showBottomSheet instead of showModalBottomSheet

Create global key and a listener

final _scaffoldKey = new GlobalKey<ScaffoldState>();
VoidCallback _showPersBottomSheetCallBack;

Write your method to show the sheet

  void _showBottomSheet() {
    setState(() {
      _showPersBottomSheetCallBack = null;
    });

    _scaffoldKey.currentState
        .showBottomSheet((context) {
      return new Container(
        height: MediaQuery.of(context).size.height-100.0,
        color: Colors.greenAccent,
        child: new Center(
          child: new Text("Hi BottomSheet"),
        ),
      );
    })
        .closed
        .whenComplete(() {
      if (mounted) {
        setState(() {
          _showPersBottomSheetCallBack = _showBottomSheet;
        });
      }
    });
  }

initialize the listener

void initState() {
    super.initState();
    _showPersBottomSheetCallBack = _showBottomSheet;
  }

Call the method wherever you required

new RaisedButton(
                  onPressed: _showPersBottomSheetCallBack,
                  child: new Text("Persistent"),
                ),

Hope it helps !

Shyju M
  • 9,387
  • 4
  • 43
  • 48
7

Lately I found an workaround for this. By setting the canvasColor property to Colors.transparent in your app's theme, we can make the BottomSheet's overlay disappear.

return new MaterialApp(
  title: 'MyApp',
  theme: new ThemeData(
    primarySwatch: Colors.blue,
    canvasColor: Colors.transparent,
  ),
  //...
);

Once you set this up, you may use ClipRRect or Decoration with rounded corners.

Bottomsheet with rounded corners

ryanafrish7
  • 3,222
  • 5
  • 20
  • 35
7

Based on Vicky's answer, Wrap could make alignments miserable. Use instead Column(mainAxisSize: MainAxisSize.min, children: [...]) in the widget. Implementing that in your example should look like:

void _showBottomSheet(BuildContext context) {
    showModalBottomSheet<Null>(
      context: context,
      builder: (BuildContext context) {
        return Column(
        mainAxisAxisSize: MainAxisSize.min,
        children: [
          _bottomSheetScreen
        ]); // defined earlier on
      },
    );
}

If you want to control the scrolls with swipes, then try setting isScrollControlled: true on the showModalBottomSheet().

Erisan Olasheni
  • 2,395
  • 17
  • 20
6

here is the simplest code working in 2021

 showModalBottomSheet(
      context: context,
      isScrollControlled: true,  // <-- make bottom sheet resize to content height
      shape: RoundedRectangleBorder(  // <-- for border radius
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(15.0),
          topRight: Radius.circular(15.0),
        ),
      ),
      builder: (BuildContext context) {
       return Container() // <-- any widget you want
      });
David Machara
  • 559
  • 9
  • 13
  • 1
    This automatically makes my bottom sheet go full-screen. I'm using a DefaultTabController & the child is a Column to layout my Tabs & TabBarView and within the TabBarView is another Column to layout my text fields and buttons. Any suggestions? My goal is to make sure this expands to show all text fields and buttons and also raise with the keyboard to make everything visible. – Luke Irvin Mar 12 '22 at 17:41
3

In the above code by @Shyju Madathil you need to add key in scaffold to make it work

return new Scaffold(
  key: _scaffoldKey,
  ....
crimson suv
  • 129
  • 1
  • 2
  • 7
2

You can adjust the height by setting the height of your main container either by a constant ex : 800 or by using MediaQuery ex :

if i want to show only 2 /3 of the screen

MediaQuery.of(context).size.height -
      (MediaQuery.of(context).size.height / 3)

for the radius first you have to set the

 showModalBottomSheet(
                          backgroundColor: Colors.transparent,

and then you container color to White or any color you wanted , example :

return Container(
  decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.only(
          topLeft: const Radius.circular(16),
          topRight: const Radius.circular(16))),
  child:
Oussaki
  • 1,449
  • 2
  • 21
  • 30
2

You can adjust the height by setting isScrollControlled: true and wrapping the BottomSheet inside FractionallySizedBox. It would look something like this:

 showModalBottomSheet<void>(
    context: context,
    //This
    isScrollControlled: true,
    builder: (BuildContext context) {
      return StatefulBuilder(
          builder: (BuildContext context, StateSetter state) {
        return FractionallySizedBox(
            //Here specify the high of the BottomSheet
            heightFactor: 0.9,
            child:BottomSheet(
            .
            .
            .
            
            .
            .
            .
      ));
      });
    });
Fahima Mokhtari
  • 1,691
  • 2
  • 16
  • 30
2

Simple way to do this:

showModalBottomSheet(
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.only(
                          topRight: Radius.circular(15),
                          topLeft: Radius.circular(15),
                        ),
                      ),
                      context: context,
                      builder: (context) {
                        return Wrap(
                          children: [
                            Container(
                              height: 40,
                              child: Center(
                                child: Text(
                                  "Edit Profile",
                                  style: TextStyle(
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),`
                              ),
                            ),                           
                          ],
                        );
                      });
Niket Tongare
  • 553
  • 6
  • 7
1

In my case, setting the 'isScrollable' parameter to "true" makes the bottomsheet go past halfway through the screen.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 30 '23 at 07:39
0

We can also use following solution:

void _showModalBottomSheet(BuildContext context) {
  showModalBottomSheet<void>(
    isScrollControlled: true,
    enableDrag: false,
    context: context,
    builder: (BuildContext context) {
      return DraggableScrollableSheet(
        expand: false,
        initialChildSize: 0.90, // Initial height as a fraction of screen height
        builder: (BuildContext context, ScrollController scrollController) {
          return Container(
            child: SingleChildScrollView(
              controller: scrollController,
              child: Column(
                children: [
                  // Content of the bottom sheet
                ],
              ),
            ),
          );
        },
      );
    },
  );
}
Akshar Patel
  • 8,998
  • 6
  • 35
  • 50
0
  showModalBottomSheet(
            isScrollControlled: true,
            context: context,
            builder: (_) => Wrap(children: [
                  Column(
                    children: [
                      Container(height: 44, color: Colors.red),
                      Container(
                        constraints: BoxConstraints(
                            maxHeight:
                                MediaQuery.of(context).size.height * 0.6),
                        child: ListView.builder(
                            shrinkWrap: true,
                            itemBuilder: (context, index) {
                              return ListTile(
                                title: Text("item $index"),
                              );
                            },
                            itemCount: 100),//***Try 3 elements***
                      )
                    ],
                  )
                ]));
Jagie
  • 2,190
  • 3
  • 27
  • 25
-1

This is my solution.It can adjust height and has a max height.If the content over max height.It can be scrolled

 showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true,
    backgroundColor: Colors.white,
    // elevation: 10,
    shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.only(
      topLeft: Radius.circular(12),
      topRight: Radius.circular(12),
    )),
    builder: (context) {
      return ConstrainedBox(
        constraints: const BoxConstraints(maxHeight: 300),
        child: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: Column(
              children: List.generate(20, (index) => Text("data$index")),
            )),
      );
    },
  );
zhimin
  • 507
  • 4
  • 5