How to create a modal bottomsheet with circular corners in Flutter?

showModalBottomSheet does not provide any styling or decorations. I want to create something like the Google Tasks bottomsheet.

google tasks bottomsheet

114993 次浏览

This is the modalBottomSheet function needed.

    void _modalBottomSheetMenu(){
showModalBottomSheet(
context: context,
builder: (builder){
return new Container(
height: 350.0,
color: Colors.transparent, //could change this to Color(0xFF737373),
//so you don't have to change MaterialApp canvasColor
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: new Center(
child: new Text("This is a modal sheet"),
)),
);
}
);
}

Also the most important part of this working properly is, in MaterialApp set canvasColor to transparent like the one shown below.

return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Tasks',
theme: new ThemeData(
primarySwatch: Colors.teal,
canvasColor: Colors.transparent,
),
home: new TasksHomePage(),
);
}

I have tested the code and it works fine as I was also making a clone of the Google Tasks app which will be opensourced in my github.

UPDATED ON 2019-08-05

You can now do it using the default showModalBottomSheet method that now supports adding a ShapeBorder and also backgroundColor!

showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
backgroundColor: Colors.white,
...
);

--

Instead of overriding the entire theme of the app (which caused problems in various parts of my app) as suggested by other answers, I decided to take a look at the implementation for showModalBottomSheet and find the problem myself. Turns out that all that was needed was wrapping the main code for the modal in a Theme widget that contains the canvasColor: Colors.transparent trick. I also made it easier to customize the radius and also the color of the modal itself.

You can use either the package on pub or a gist containing the same code. Don't forget to import the proper package/file.

showRoundedModalBottomSheet(
context: context,
radius: 20.0,  // This is the default
color: Colors.white,  // Also default
builder: (context) => ???,
);

You can now simply set the shape argument. Example:

showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
context: context,
builder: (context) => MyBottomSheet(),
);

Putting together all the answers before, I could achieve the best result possible (in my opinion) for this.

showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15.0), topRight: Radius.circular(15.0)),
),
builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.email),
title: Text('Send email'),
onTap: () {
print('Send email');
},
),
ListTile(
leading: Icon(Icons.phone),
title: Text('Call phone'),
onTap: () {
print('Call phone');
},
),
],
);
});
    showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (ctx) {
return Container(
decoration: BoxDecoration(
color: Colors.green, // or some other color
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0)
)
);
});

Just answered a related question

You can add corners to your bottomSheet and expand your bottomSheet according to content present inside it (not restricted to half size of screen)

check out the answer here

https://stackoverflow.com/a/59541927/9236994

I think the best way to do a rounded-corner modal is to use a RoundedRectangleBorder with a vertical BorderRadius, setting only its top property:

showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
builder: (BuildContext context) {
// return your layout
});

Using separate radii for top left and top right is a bit more verbose and error-prone.

i have this code and work well for me. please check it and let me know you'r opinion.

showBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
context: context,
builder: (context) => Container(
height: 250,


child: new Container(
decoration: new BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: new Center(
child: new Text("This is a modal sheet"),
)),
))
showModalBottomSheet(
context:context
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
)

You can add a RoundedRectangleBorder widget inside the showModalBottomSheet:

showModalBottomSheet<void>(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0)
),
),
)

You can give borderRadius in decoration container also.

 showModalBottomSheet(
context: context,
builder: (builder){
return  Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(15.0),
topRight: const Radius.circular(15.0))),
child: Center(
child: Text("This is a modal sheet"),
),
);
}
);

for persistent bottom sheet, add the following code in the material app widget's theme property

ThemeData(
bottomSheetTheme: BottomSheetThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
showModalBottomSheet(
context:context
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.hardEdge,
)

It will be much better to use Clip.hardEdge. As it is faster than other clipping modes but slower than [none].

Set the shape to RoundedRectangleBorder should work, but sometimes the content overflows making round corners missing, when this happens set clipBehavior to Clip.antiAlias to resolve.

showModalBottomSheet(
isScrollControlled: true,
backgroundColor: colorOnPrimary,
// set this when inner content overflows, making RoundedRectangleBorder not working as expected
clipBehavior: Clip.antiAlias,
// set shape to make top corners rounded
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
context: context,
builder: (context) {
return SingleChildScrollView(
child: Container(),
);
},
)

one way is by usingshowModalBottomSheet shape property,

showModalBottomSheet(
context:context
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0),
),
),
)

you can now do it with the showModelBottomSheet() widget parameter shape

showModalBottomSheet<void>(
shape: const RoundedRectangleBorder(
borderRadius:  BorderRadius.only(topLeft:
Radius.circular(24),topRight:Radius.circular(24) ),),
context: context,
builder: (BuildContext context) {}

use the showModalBottomSheet

shape:

property which takes ShapeBorder as shown below

 shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),

enter image description here