Reputation: 20465
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.
Upvotes: 121
Views: 163105
Reputation: 4779
To set the border radius pass the shape
property of showModalBottomSheet
method and configure the required type of shape and border radius.
For e.g. below will get a RoundedRectangle boarder with cirular border of radius 28 on topLeft and topRight
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(28), topRight: Radius.circular(28)),
),
return showModalBottomSheet<String>(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(28), topRight: Radius.circular(28)),
),
context: context,
builder: (context) {
return _BottomSheetContents(
items: items,
label: label,
);
},
);
And below is the _BottomSheetContents
Widget code
class _BottomSheetContents extends StatelessWidget {
const _BottomSheetContents({required this.items, required this.label, super.key});
final List<String> items;
final String label;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Text(label),
),
ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) => ListTile(
title: Text(items[index]),
visualDensity: VisualDensity.compact,
onTap: () => context.navigator.pop(item),
),
),
],
);
}
}
Upvotes: 0
Reputation: 68
showModalBottomSheet( isScrollControlled: false, // <= set to false. scrollControlDisabledMaxHeightRatio: 0.8, context: context, builder: (context) => yourWidget() );
you can use this by setting scroll control to false
and then pass this line
scrollControlDisabledMaxHeightRatio: 0.8,
according to height which you want set it
Upvotes: 0
Reputation: 7207
You have to:
isScrollControlled: true
For example, this modal bottom sheet takes up 95% of the screen height:
import 'package:sizer/sizer.dart';
// ...
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) => SizedBox(
height: 95.h,
child: YourWidget(),
),
);
In the value 95.h
, h
extension method from the sizer package, which allows you to specify values in terms of the screen size.
Upvotes: 1
Reputation: 21
Make isScrollControlled : true and use Wrap widget around your page
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return const Wrap(children: [Page()]);
},
);
Upvotes: 2
Reputation: 2220
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***
)
],
)
]));
Upvotes: 0
Reputation: 9388
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
],
),
),
);
},
);
},
);
}
Upvotes: 1
Reputation: 11
In my case, setting the 'isScrollable' parameter to "true" makes the bottomsheet go past halfway through the screen.
Upvotes: 1
Reputation: 2905
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()
.
Upvotes: 8
Reputation: 517
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")),
)),
);
},
);
Upvotes: -1
Reputation: 367
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()
);
Upvotes: 17
Reputation: 20249
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)))),
);
}
Upvotes: 26
Reputation: 632
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,
),
),`
),
),
],
);
});
Upvotes: 3
Reputation: 1983
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.
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'),
],
),
),
);
});
}
Upvotes: 28
Reputation: 2062
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(
.
.
.
.
.
.
));
});
});
Upvotes: 2
Reputation: 589
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
});
Upvotes: 6
Reputation: 546
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();
}
)
Upvotes: 13
Reputation: 2932
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"),
),
),
);
isScrollControlled: true
and backgroundColor: Colors.transparent
for the modalContainer
with required height:
as root widget to modal builderBoxDecoration
with required borderRadius
for the Container
Upvotes: 114
Reputation: 10985
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(),
),
)
]
)
}
)
Upvotes: 242
Reputation: 1649
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:
Upvotes: 2
Reputation: 179
In the above code by @Shyju Madathil you need to add key in scaffold to make it work
return new Scaffold(
key: _scaffoldKey,
....
Upvotes: 4
Reputation: 3410
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.
Upvotes: 7
Reputation: 9943
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 !
Upvotes: 10