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.
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)
],
),
);
}
}
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.
I'm currently trying to make my appBar appear like the picture below but seem to be running into one particular issue every time I try doing so.
I have given the appBar a height of 100 and my idea was to distribute the height in a 40 60 ratio between the two Containers(amber and red). Things look fine when there's only the amber Container but as soon as I try adding the red Container, the amber Container somehow gets pushed up behind the status bar and I have no idea what is causing this.
This is till the point things look great with the amber Container
This is when the above anomaly occurs
This is my code. (the part commented out is the design for the Red Container)
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
bool _toggleDropDown = false;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: AppBar(
elevation: 0,
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
backgroundColor: Colors.green,
titleSpacing: 0,
title: Column(
children: [
Container( //Amber Container
width: double.infinity,
height: 40,
color: Colors.amber,
child: Column(
children: [
Container(
padding: const EdgeInsets.only(left: 5),
height: 15,
width: double.infinity,
// color: Colors.red,
child: const Text(
'Delivering To',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 15),
),
),
Container(
height: 25,
width: double.infinity,
padding: const EdgeInsets.only(left: 5),
// color: Colors.blue,
child: Row(
children: [
const Text(
'Current Location',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold),
),
const SizedBox(width: 20),
Container(
height: double.infinity,
width: 20,
// color: Colors.yellow,
child: InkWell(
onTap: () {
setState(() {
_toggleDropDown = !_toggleDropDown;
});
},
child: Icon(
!_toggleDropDown
? Icons.keyboard_arrow_down
: Icons.keyboard_arrow_up,
color: Colors.red,
),
))
],
),
),
],
),
),
// Container( //Red Container
// height: 60,
// width: double.infinity,
// color: Colors.red,
// padding: EdgeInsets.only(top: 8),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// InkWell(
// onTap: () {},
// child: Icon(
// Icons.search,
// size: 25,
// )),
// Row(
// children: [
// InkWell(
// onTap: () {},
// child: const Icon(
// Icons.shopping_cart_outlined,
// color: Colors.white,
// size: 25,
// ),
// ),
// InkWell(
// onTap: () {},
// child: const Icon(
// Icons.notifications_none_outlined,
// color: Colors.white,
// size: 25,
// ),
// )
// ],
// )
// ],
// ),
// )
],
)),
),
);
}
}
FYI : I have also tried wrapping the Scaffold with SafeArea and the output that produces looks like this:
The issue is here AppBar is not getting height:100. While using PreferredSize you can just use Column or just using toolbarHeight: 100 on AppBar.
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: AppBar(
elevation: 0,
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
backgroundColor: Colors.green,
titleSpacing: 0,
toolbarHeight: 100, //<this
Or just do
return Scaffold(
appBar: AppBar(
elevation: 0,
toolbarHeight: 100, //<this
The trick lies in wrapping your Scaffold() with a SafeArea() widget.
Scaffold represents the whole screen of a device, each and every pixel of your screen.
SafeArea takes into account notches, status bars, bottom navigation bars and bottom navigation buttons.
Here's a quick how-to:
class _MyScreenState extends State<DonationDetails> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(), //your ui components goes here
));
}
}
UPDATE TO YOUR USE CASE
import 'package:flutter/material.dart';
class HomeScreenTest extends StatefulWidget {
HomeScreenTestState createState() => HomeScreenTestState();
}
class HomeScreenTestState extends State<HomeScreenTest> {
bool _toggleDropDown = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
leading: null,
backgroundColor: Colors.green,
titleSpacing: 0,
title: Container(
width: double.infinity,
height: 40,
color: Colors.amber,
child: Column(
children: [
Container(
padding: const EdgeInsets.only(left: 5),
height: 15,
width: double.infinity,
// color: Colors.red,
child: const Text(
'Delivering To',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 15),
),
),
Container(
height: 25,
width: double.infinity,
padding: const EdgeInsets.only(left: 5),
// color: Colors.blue,
child: Row(
children: [
const Text(
'Current Location',
style: TextStyle(
color: Colors.grey, fontWeight: FontWeight.bold),
),
const SizedBox(width: 20),
Container(
height: double.infinity,
width: 20,
// color: Colors.yellow,
child: InkWell(
onTap: () {
setState(() {
_toggleDropDown = !_toggleDropDown;
});
},
child: Icon(
!_toggleDropDown
? Icons.keyboard_arrow_down
: Icons.keyboard_arrow_up,
color: Colors.red,
),
))
],
),
),
],
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: Container(
//Red Container
height: 60,
width: double.infinity,
color: Colors.red,
padding: EdgeInsets.only(top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(
onPressed: () {},
icon: Icon(
Icons.shopping_cart_outlined,
color: Colors.white,
size: 25,
),
),
Row(
children: [
IconButton(
onPressed: () {},
icon: Icon(
Icons.shopping_cart_outlined,
color: Colors.white,
size: 25,
),
),
IconButton(
onPressed: () {},
icon: Icon(
Icons.notifications_none_outlined,
color: Colors.white,
size: 25,
),
),
],
)
],
),
),
),
),
),
);
}
}
You can use bottom in 'AppBar'.
Move the red Container to bottom with PreferredSize widget as parent. like this.
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: AppBar(
elevation: 0,
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
backgroundColor: Colors.green,
titleSpacing: 0,
title: Container(
//Amber Container
width: double.infinity,
height: 40,
color: Colors.amber,
child: Column(
children: [
Container(
padding: const EdgeInsets.only(left: 5),
height: 15,
width: double.infinity,
// color: Colors.red,
child: const Text(
'Delivering To',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 15),
),
),
Container(
height: 25,
width: double.infinity,
padding: const EdgeInsets.only(left: 5),
// color: Colors.blue,
child: Row(
children: [
const Text(
'Current Location',
style: TextStyle(
color: Colors.grey, fontWeight: FontWeight.bold),
),
const SizedBox(width: 20),
Container(
height: double.infinity,
width: 20,
// color: Colors.yellow,
child: InkWell(
onTap: () {
setState(() {
_toggleDropDown = !_toggleDropDown;
});
},
child: Icon(
!_toggleDropDown
? Icons.keyboard_arrow_down
: Icons.keyboard_arrow_up,
color: Colors.red,
),
))
],
),
),
],
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: Container(
//Red Container
height: 60,
width: double.infinity,
color: Colors.red,
padding: EdgeInsets.only(top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {},
child: Icon(
Icons.search,
size: 25,
)),
Row(
children: [
InkWell(
onTap: () {},
child: const Icon(
Icons.shopping_cart_outlined,
color: Colors.white,
size: 25,
),
),
InkWell(
onTap: () {},
child: const Icon(
Icons.notifications_none_outlined,
color: Colors.white,
size: 25,
),
)
],
)
],
),
),
),
),
),
);
I'm really new to Flutter. In the homepage, I intend to build the page something like this:
The other widgets are working pretty fine, but when I come to developing the double button like the design that overlapping the container widgets below, it's not working at all.
My first approach is using Stack which contain Positioned widgets (for the double button) and Container (for the other things). But, the Positioned widgets despite having a dummy child widget is not visible at all, whereas the Container is perfectly working. I don't know whether the Positioned is written in a wrong way, or else.
Here's the source code:
https://github.com/andre-nk23/packme/blob/master/lib/main.dart
Can anyone help me here? To make those two button overlapping the container? Thank you.
Note : I'm using several imported packages, please notify me if those packages affects the process of developing the overlap double button.
void main() => runApp(MaterialApp(
home: BottomNavBar(),
));
class BottomNavBar extends StatefulWidget {
#override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: unused_field
int _page = 0;
String tabAccent = '#B9EEDC';
String pinkAccent = '#FF8787';
String greenAccent = '#43D1A5';
String blueAccent = '#030835';
String buttonAccent = '#CDF0E0';
GlobalKey _bottomNavigationKey = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
drawer: new Drawer(
child: ListView(
children: [
Container(
height: 210,
child: DrawerHeader(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CircleAvatar(
backgroundImage: AssetImage('assets/img.jpeg'),
maxRadius: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Julian Casablancas',
textScaleFactor: 1.6,
),
Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Text(
'julian.c#gmail.com',
textScaleFactor: 1.1,
),
)
],
)
]),
decoration: BoxDecoration(color: HexColor('#CDF0E0')),
),
),
ListTile(
leading: Icon(FeatherIcons.home, color: HexColor('#030835')),
title: Text('Beranda', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE'),
),
ListTile(
leading: Icon(Icons.person_outlined,
size: 25, color: HexColor('#030835')),
title: Text('Profil', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading: Icon(FeatherIcons.clock, color: HexColor('#030835')),
title: Text('Riwayat', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading: Icon(FeatherIcons.moon, color: HexColor('#030835')),
title: Text('Mode gelap', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading: Icon(Icons.attach_money, color: HexColor('#030835')),
title: Text('Gabung kami', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading: Icon(Icons.info_outline_rounded,
color: HexColor('#030835')),
title: Text('Informasi', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading:
Icon(Icons.settings_outlined, color: HexColor('#030835')),
title: Text('Pengaturan', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
ListTile(
leading: Icon(Icons.logout, color: HexColor('#030835')),
title: Text('Keluar', textScaleFactor: 1.2),
tileColor: HexColor('#CDF0E0'),
selectedTileColor: HexColor('#A4E7CE')),
],
),
),
appBar: PreferredSize(
preferredSize: Size.fromHeight(80.0),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
leading: Padding(
padding: EdgeInsets.fromLTRB(20, 20, 0, 0),
child: new IconButton(
icon: new Icon(Icons.donut_large_rounded,
size: 25, color: HexColor('#030835')),
onPressed: () => _scaffoldKey.currentState.openDrawer(),
color: HexColor('#B9EEDC')),
),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 30, 0),
child: Image(
image: AssetImage('assets/img.jpeg'),
height: 40,
),
),
],
),
),
bottomNavigationBar: CurvedNavigationBar(
key: _bottomNavigationKey,
index: 0,
height: 60.0,
items: <Widget>[
Icon(Icons.qr_code_rounded, size: 30),
Icon(Icons.attach_money_rounded, size: 30),
Icon(FeatherIcons.box, size: 30),
],
color: HexColor('#B9EEDC'),
buttonBackgroundColor: HexColor('#B9EEDC'),
backgroundColor: HexColor('#ECFBF4'),
animationCurve: Curves.easeInOut,
animationDuration: Duration(milliseconds: 300),
onTap: (index) {
setState(() {
_page = index;
});
},
),
body: SafeArea(
child: Container(
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(overflow: Overflow.visible, children: <Widget>[
Container(
margin: EdgeInsets.only(top: 25.0),
width: 500,
color: HexColor('#ECFBF4'),
child: Padding(
padding: EdgeInsets.fromLTRB(30, 35, 30, 55),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(FeatherIcons.info, size: 25),
Icon(FeatherIcons.clock, size: 25)
],
),
SizedBox(height: 10),
Text(
'Scan QR',
style: GoogleFonts.poppins(
textStyle: Theme.of(context).textTheme.headline1,
fontSize: 28,
fontWeight: FontWeight.w700,
color: HexColor('#030835'),
),
),
SizedBox(height: 2),
Text(
'di restoran / driver',
style: GoogleFonts.poppins(
textStyle: Theme.of(context).textTheme.headline1,
fontSize: 18,
fontWeight: FontWeight.w400,
color: HexColor('#030835'),
),
),
Text(
'untuk mulai meminjam',
style: GoogleFonts.poppins(
textStyle: Theme.of(context).textTheme.headline1,
fontSize: 18,
fontWeight: FontWeight.w400,
color: HexColor('#030835'),
),
),
],
),
),
),
/* Here are the changes */
Positioned(
left: 75,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.check_box),
),
),
Positioned(
right: 75,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.check_box),
),
),
]),
],
),
),
),
);
}
}
Hello Andrea, this is the necessary code which you can implement perfectly. Well, I have removed the redundant widgets which was been used to make the code cleaner.The stack was used by me to implement your question.
Have you tried Stack? You can approach this many ways, I just made this in a rush.have a look
Container(
height: 280,
width: 400,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Container(
height: 250,
width: 400,
decoration: BoxDecoration(
color: Colors.pinkAccent,
borderRadius: BorderRadius.only(
topRight: Radius.circular(30),
topLeft: Radius.circular(30),
)
),
),
),
Positioned(
top: 0,
right: 100,
child: FloatingActionButton(
onPressed: (){},
child: Icon(
Icons.check_box
),
),
),
Positioned(
top: 0,
left: 100,
child: FloatingActionButton(
onPressed: (){},
child: Icon(
Icons.check_box
),
),
),
],
),
)
Use Row For Positioning both of the Buttons in container.
Container(
height: 280,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Container(
height: 250,
width: 400,
decoration: BoxDecoration(
color: Colors.pinkAccent,
),
),
),
Positioned(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
FloatingActionButton(
onPressed: (){},
child: Icon(
Icons.person
),
),
FloatingActionButton(
onPressed: (){},
child: Icon(
Icons.face
),
),
],
),
),
],
),
)