I am using a dynamic bottom sheet with a column as its child. The last child of this column is a grid view. For some small screen devices, the content of this bottom sheet my get overflow so I wrapped the grid view inside an expanded widget. Now its content are scrollable if they are overflowing.
But the problem here is, even if the contents of the grid view are not overflowing (screen size is big enough) it still expands to full screen leaving empty space at the bottom. I am trying to solve this issue for past 3 days but no result. I tried various combinations of parent and child widget but nothing gives the satisfying result.
The result I am expecting is that the grid view should scroll when contents are overflowing and if not then it should take only the required space and not the entire screen.
Here is my entire code, the grid view with the problem is at the end :
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return Container(
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color.fromARGB(255, 225, 225, 225)),
),
//color: Color.fromARGB(255, 255, 255, 255),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(15, 15, 10, 15),
child: Icon(
Icons.save,
color: Color.fromARGB(255, 2, 136, 209),
size: 28.0,
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: (){},
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 13.0, 10.0, 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(minWidth: 0, maxWidth: MediaQuery.of(context).size.width*(2/3)),
child: Text(
'PDF Name',
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 0.0),
child: Icon(
Icons.edit,
color: Color.fromARGB(255, 2, 136, 209),
size: 16.0,
),
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
child: Text(
"PDF Size",
style: TextStyle(
fontSize: 12.0,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
],
),
),
),
),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 4),
child: Text(
"Share/Save File to",
style: TextStyle(
color: Color.fromARGB(255, 117, 117, 117),
fontSize: 15.0,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
]
),
Expanded(
child: GridView.count(
padding: EdgeInsets.fromLTRB(0, 0, 0, 15),
crossAxisCount: 3,
shrinkWrap: true,
childAspectRatio: 1.25,
children: <Widget>[
FileSaveCard(icon: Icons.phone_android, color: Colors.pink, title: 'Internal Storage', press: (){}),
FileSaveCard(icon: Icons.folder, color: Colors.blueAccent, title: 'My Documents', press: (){}),
FileSaveCard(icon: Icons.add_to_drive_rounded, color: Color.fromARGB(255, 254, 150, 0), title: 'Google Drive', press: (){}),
FileSaveCard(icon: Icons.mail, color: Colors.lightBlue, title: 'Send to Email', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
],
),
),
],
),
);
}
);
},
);
Here is the output image:
It even slides under that phone's status bar at the top. How can I avoid that as well.
This is the result I am expecting:
Case 1: When it is overflowing, this works fine as I have wrapped grid view in an expanded widget, it becomes scrollable -
Case 2: When screen size is sufficient for the children, below image should be the output, but I get empty space at bottom instead-
Okay, I figured it out finally. For the Status Bar overlapping part giving safe area and all was not working and as suggested by Sagar Acharya using FractionallySizedBox did prevented it but it forced the bottom sheet to take up full screen irrespective of its content height leaving empty space after its last item. Instead I used constraints: BoxConstraints(maxHeight: (MediaQuery.of(context).size.height)*0.95) which did not force sheet to take full height and also prevented it from overlapping status bar.
For the other problem I first removed expanded from top of my grid view and wrapped my whole column (containing all items of the bottom sheet) with SingleChildScrollView. Now it keeps the content wrapped until sheet reaches full screen height and when it does it becomes scrollable.
But still there is one thing I want to change, in my output my whole content of the bottom sheet is scrollable but I just want the grid view children to be scrollable, the top most 'PDF Name' and 'Share/Save File to' should not scroll along with it. Any ideas how I can do that. I tried using SingleChildScrollView on grid view instead of Column but it did not work (the element overflowed when the sheet reached full height)
Here is my code:
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return Container(
//height: 900,
constraints: BoxConstraints(maxHeight: (MediaQuery.of(context).size.height)*0.95),
color: Colors.white,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color.fromARGB(255, 225, 225, 225)),
),
//color: Color.fromARGB(255, 255, 255, 255),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(15, 15, 10, 15),
child: Icon(
Icons.save,
color: Color.fromARGB(255, 2, 136, 209),
size: 28.0,
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: (){},
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 13.0, 10.0, 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(minWidth: 0, maxWidth: MediaQuery.of(context).size.width*(2/3)),
child: Text(
'PDF Name',
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 0.0),
child: Icon(
Icons.edit,
color: Color.fromARGB(255, 2, 136, 209),
size: 16.0,
),
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
child: Text(
"PDF Size",
style: TextStyle(
fontSize: 12.0,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
],
),
),
),
),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 4),
child: Text(
"Share/Save File to",
style: TextStyle(
color: Color.fromARGB(255, 117, 117, 117),
fontSize: 15.0,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
]
),
GridView.count(
padding: EdgeInsets.fromLTRB(0, 0, 0, 15),
crossAxisCount: 3,
shrinkWrap: true,
//physics: NeverScrollableScrollPhysics(),
physics: const ScrollPhysics(),
childAspectRatio: 1.25,
children: <Widget>[
FileSaveCard(icon: Icons.phone_android, color: Colors.pink, title: 'Internal Storage', press: (){}),
FileSaveCard(icon: Icons.folder, color: Colors.blueAccent, title: 'My Documents', press: (){}),
FileSaveCard(icon: Icons.add_to_drive_rounded, color: Color.fromARGB(255, 254, 150, 0), title: 'Google Drive', press: (){}),
FileSaveCard(icon: Icons.mail, color: Colors.lightBlue, title: 'Send to Email', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
/*FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),*/
],
),
],
),
),
);
}
);
},
);
Any help would me much appreciated. Thank you.
CodePudding user response:
Ok So from the code i see you are using things in wrong manner.
If you are using the isScrollControlled =true it will use the complete height of the device as you have used the expanded and the Column widget as a parent for the children inside it.
Next if you do not want the complete height so instead of column you have to use the Wrap widget and remove the expanded from the gridview it will take the height as per the children.
If you want the fill modelsheet and the space from top as it overlaps the statusbar you can use the FractionallySizedBox widget
FractionallySizedBox(
heightFactor: 0.95,// This will take 0.05 percent height from the top and show the status bar
)
Note: It can only be used when the isScrolled is true.
so I have created the example from the code that you have provided, Also i have added my icon set so change it as per your needs.
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final items = <Widget>[
//1
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//2
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//3
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//4
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//5
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//6
const Icon(
Icons.phone_android,
color: Colors.pink,
semanticLabel: 'Internal Storage',
),
//Add the same item below this to make it full screen and items below 7 will have the minimum model sheet height.
//7
// const Icon(
// Icons.phone_android,
// color: Colors.pink,
// semanticLabel: 'Internal Storage',
// ),
//
// FileSaveCard(icon: Icons.folder, color: Colors.blueAccent, title: 'My Documents', press: (){}),
// FileSaveCard(icon: Icons.add_to_drive_rounded, color: Color.fromARGB(255, 254, 150, 0), title: 'Google Drive', press: (){}),
// FileSaveCard(icon: Icons.mail, color: Colors.lightBlue, title: 'Send to Email', press: (){}),
// FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
];
@override
Widget build(BuildContext context) {
return SafeArea(
top: true,
child: Scaffold(
body: ElevatedButton(
onPressed: () {
showModalBottomSheet<dynamic>(
// use only when you want to use the full height of the screen.
isScrollControlled: items.length > 6 ? true : false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context, setState) {
return FractionallySizedBox(
heightFactor: items.length > 6
? 0.95
: null, // This widget will add padding from top showing the status bar
child: Container(
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Color.fromARGB(255, 225, 225, 225)),
),
//color: Color.fromARGB(255, 255, 255, 255),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
const EdgeInsets.fromLTRB(15, 15, 10, 15),
child: Icon(
Icons.save,
color: Color.fromARGB(255, 2, 136, 209),
size: 28.0,
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.fromLTRB(
8.0, 13.0, 10.0, 10.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(
minWidth: 0,
maxWidth:
MediaQuery.of(context)
.size
.width *
(2 / 3)),
child: Text(
'PDF Name',
overflow:
TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: TextStyle(
fontSize: 16.0,
fontWeight:
FontWeight.bold,
color: Color.fromARGB(
255, 117, 117, 117),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(
5.0, 0.0, 0.0, 0.0),
child: Icon(
Icons.edit,
color: Color.fromARGB(
255, 2, 136, 209),
size: 16.0,
),
),
],
),
Padding(
padding:
const EdgeInsets.fromLTRB(
0.0, 5.0, 0.0, 0.0),
child: Text(
"PDF Size",
style: TextStyle(
fontSize: 12.0,
color: Color.fromARGB(
255, 117, 117, 117),
),
),
),
],
),
),
),
),
),
],
),
),
Row(children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 4),
child: Text(
"Share/Save File to",
style: TextStyle(
color: Color.fromARGB(255, 117, 117, 117),
fontSize: 15.0,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)),
]),
Expanded(
flex: items.length > 6 ? 1 : 0,
child: GridView.count(
padding: EdgeInsets.fromLTRB(0, 0, 0, 15),
crossAxisCount: 3,
shrinkWrap: true,
childAspectRatio: 1.25,
physics: const ScrollPhysics(),
children: items),
),
],
),
),
);
});
},
);
},
child: const Text("Press"),
),
),
);
}
}
Run the application and let me know if that works for you.
CodePudding user response:
please accept and vote the answer if its helps you
- I think this is the answer you wanted
import 'package:flutter/material.dart';
import 'package:test11111/test1.dart';
import 'package:get/get.dart';
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: Get.height* 0.4,
color: Colors.white,
child: Column(
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Color.fromARGB(255, 225, 225, 225)),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(15, 15, 10, 15),
child: Icon(
Icons.save,
color: Color.fromARGB(255, 2, 136, 209),
size: 28.0,
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: (){},
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 13.0, 10.0, 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(minWidth: 0, maxWidth: MediaQuery.of(context).size.width*(2/3)),
child: Text(
'PDF Name',
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 0.0),
child: Icon(
Icons.edit,
color: Color.fromARGB(255, 2, 136, 209),
size: 16.0,
),
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
child: Text(
"PDF Size",
style: TextStyle(
fontSize: 12.0,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
],
),
),
),
),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 4),
child: Text(
"Share/Save File to",
style: TextStyle(
color: Color.fromARGB(255, 117, 117, 117),
fontSize: 15.0,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 4),
child: Divider(
color: Color.fromARGB(255, 220, 220, 220),
thickness: 1.1,
),
)
),
]
),
Expanded(
child: GridView.count(
padding: EdgeInsets.fromLTRB(0, 0, 0, 15),
crossAxisCount: 3,
shrinkWrap: true,
childAspectRatio: 1.25,
children: <Widget>[
FileSaveCard(icon: Icons.phone_android, color: Colors.pink, title: 'Internal Storage', press: (){}),
FileSaveCard(icon: Icons.folder, color: Colors.blueAccent, title: 'My Documents', press: (){}),
FileSaveCard(icon: Icons.add_to_drive_rounded, color: Color.fromARGB(255, 254, 150, 0), title: 'Google Drive', press: (){}),
FileSaveCard(icon: Icons.mail, color: Colors.lightBlue, title: 'Send to Email', press: (){}),
FileSaveCard(icon: Icons.share, color: Colors.green, title: 'Share', press: (){}),
],
),
),
],
),
),
],
),
);
},
);
},
),
);
}
}
class FileSaveCard extends StatelessWidget {
FileSaveCard(
{Key? key,
required this.icon,
required this.color,
required this.title,
required this.press})
: super(key: key);
IconData icon;
Color color;
String title;
VoidCallback press;
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
IconButton(icon: Icon(icon), color: color, onPressed: press),
Text(title)
],
),
);
}
}