Flutter modal bottom sheet full height - flutter

I was trying things out with ModalBottomSheet. How can I achieve 90% height of device screen size for modal sheet. I did mediaquery but still it does not give me more than half of the screen size. How do I solve this?
Here is the code:
class _TestFileState extends State<TestFile> {
modalSheet() {
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.max,
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');
},
),
],
);
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Center(child: Text('Testing Modal Sheet')),
),
body: Center(
child: InkWell(
onTap: () {
modalSheet();
},
child: Container(
color: Colors.indigo,
height: 40,
width: 100,
child: Center(
child: Text(
'Click Me',
style: TextStyle(color: Colors.white),
),
)),
),
),
),
);
}
}
Here is the output:

you have to pass isScrollControlled: true and use mediaquery as given below
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height * 0.5,
color: Colors.red,
//height: MediaQuery.of(context).size.height,
);
});

As I remember that's a restriction about the native implementation of Flutter modal bottom sheet.
You can use the package modal_bottom_sheet to achieve that.
Install:
dependencies:
modal_bottom_sheet: ^0.2.2
And minimal example:
showMaterialModalBottomSheet(
context: context,
expand: true, //this param expands full screen
builder: (context, scrollController) => Container(),
)

Related

How to call flutter dialog from separate class?

I need to separate my dialog to separate widgets an call from anywhere on some button click. Now my code looks like:
import 'package:flutter/material.dart';
class PlacesListScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _Map();
}
}
class _Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<_Map> {
final _titleController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App name'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Dialog title",
textAlign: TextAlign.center,
),
content: TextField(
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
},
child: Text("Yes"),
),
],
),
);
},
),
],
),
body: Text('App body here'),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FloatingActionButton(
onPressed: () => Text('Here will be called dialog function'),
child: Icon(Icons.add, color: Colors.white),
backgroundColor: Colors.green,
heroTag: 'mapZoomIn',
),
],
),
);
}
}
Now how I can this part of code (calling dialog) separate to another widget and call then using created widget.
showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
Firstly, you can refactor your StatefulBuilder(builder: (BuildContext context, StateSetter setState) { return AlertDialog(... into one separate widget like MyFancyDialog extends StatefulWidget. Then just call showDialog(..., MyFancyWidget()) when you need it.
Secondly, if you do not want the first method, you can extract the whole showDialog(...) into a function like void showMyFancyDialog() { showDialog... }. Is it also OK, since in dart functions are first class.
Did you try to create a new Stateful widget class at the bottom of your code and try to call that widget? If you didn't try that,
Go to under of your code and create a new Stateful class. (Let's say that myDialog)
Add the code that you want to call, inside of your "myDialog" widget
Go for where you want to call that code and try to call that class.
Hope this works for you.
Create a separate file. Import material package.
then create "Widget myDialog(context){ // paste your showDialog code here }"
Now your myDialog widget has been ready for using anywhere on whole project just import and call it.
When you call it pass BuildContext in its argument.
Its work for me.

Flutter - whitespaces displaying for image in portrait and landscape

I keep seeing lot of white space if I do landscape or portrait within my image. I do need the slidable so didn't want to tweak the code too much, but I do want it to look representable
is there something wrong with my code?
I did add a picture this is happening in both landscape and portrait mode
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text(
"1 Alif-laam-meem آلم, Pg2",
style: new TextStyle(color: styling.appBarTextcolor),
),
leading: new IconButton(
icon: new Icon(styling.appBarBackArrowIcon),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NavDrawer(),
));
})),
body: LayoutBuilder(builder:
(BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: Stack(children: <Widget>[
new Slidable(
delegate: new SlidableDrawerDelegate(),
actionExtentRatio: styling.sizeofenglishandforward,
child: SafeArea(
top: true,
bottom: true,
right: true,
left: true,
child: new Container(
child: new Image.asset(
"test/assets/Para 1 - Alif-laam-meem no color/quranpg2-1.png",
// fit: BoxFit.fitidth,
fit: BoxFit.cover,
),
),
),
actions: <Widget>[
new IconSlideAction(
caption: styling.englishIconText,
color: styling.englishIconColorstripe,
icon: styling.englishIcon,
foregroundColor: styling.englishIconColor,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Changepg2topg2Color()),
);
}),
new IconSlideAction(
caption: styling.forwardIconText,
color: styling.forwardIconColorstripe,
icon: styling.forwardIcon,
foregroundColor: styling.forwardIconColor,
// onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Changepg2topg3()),
// );
// }
),
// ),
],
secondaryActions: <Widget>[
new IconSlideAction(
caption: styling.backIconText,
color: styling.backIconColorstripe,
icon: styling.backIcon,
foregroundColor: styling.backIconColor,
// onTap: () => _showSnackBar('More'),
),
new IconSlideAction(
caption: styling.arabicIconText,
color: styling.arabicIconColorstripe,
icon: styling.arabicIcon,
foregroundColor: styling.arabicIconColor,
// onTap: () =>
),
],
),
]));
}));
}
}
SafeArea is preventing your image to go at some restricted areas of screen like, underneath the notch area. Or for some devices there are NavigationKeys in the bottom of screen. Try removing these
Cheers :)
child: SafeArea(
top: true,
bottom: true,
right: true,
left: true,

Show CircularProgressIndicator in front in Flutter

I want to display a circular bar like loading in front of other widgets.
Below is the code which i am currently using. It shows the Circular loading but its between other widget.
It should be on top. Based on the suggestion I tried using Stack but it is still showing in between the widget. What am I doing wrong here?
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool visible = true ; //Testing purpose it is true. Actually it is false.
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Stack(
children: <Widget>[
new Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: FractionalOffset.bottomCenter,//Alignment.bottomLeft,
colors: [Colors.green[900], Colors.lightBlueAccent]),
),
),SingleChildScrollView(
child: new Form(
key: _formKey,
autovalidate: _autoValidate,
child: Center(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
VerticalText(),
TextLogin(),
],
),
Divider(),
Container(
width: 280,
),
Container(
width: 280,
child: TextFormField(
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Email',
fillColor: Colors.lightBlueAccent,
labelText: 'Email',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
controller: emailController,
autocorrect: true,
validator: validateEmail,
onSaved: (String val) {
_email = val;
},
)
),
Container(
width: 280,
child: TextFormField(
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Password',
fillColor: Colors.lightBlueAccent,
labelText: 'Password',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
controller: passwordController,
autocorrect: true,
obscureText: true,
validator: validatePassword,
onSaved: (String val) {
_password = val;
},
)
),
RaisedButton(
onPressed: _validateInputs,
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Text('Login'),
),
Visibility(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
],
),
),
visible: visible,
),
],
),
)
)
)
],
),
);
}
I have seen similar questions in SO but still getting hard time to resolve it.
How to work with progress indicator in flutter?
flutter how to get a circular progress indicator working
Flutter : create an overlay progress bar
How to display CircularProgressIndicator on top of all widget in a centre of the screen
The real meaning of circularProgressIndicator is to be run while loading process without letting user interrupt.
To remove interruption by user in between, one should put circularProgressIndicator in a dialog with property barrierDismissible: false.
One should create this loading indicator as reusable widget.
You can craete a method like below and can use it anywhere over the screen without defining in screen. (this does not require stack also.). Dialog will appear on the center of the screen.
buildShowDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(),
);
});
}
For Reference: Checkout code below:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Demo(),
);
}
}
class Demo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Circle Progress Indicator Demo"),
),
body: Center(
child: MaterialButton(
child: Text("Press Me!"),
onPressed: () => buildShowDialog(context),
),
),
);
}
buildShowDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(),
);
});
}
}
Output:
Like said, the real meaning of CircularProgressIndicator is to be run while loading a process without letting user interrupt.
Create this loading indicator as a reusable .dart file.
With this you can use the LoadingIndicator flexible everywhere and overlay the current screen.
You just have to make a .dart file containing:
import 'package:flutter/material.dart';
buildLoading(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
);
});
}
Then you can use it anywhere using
buildLoading(context);
and dismiss it when loading is done using
Navigator.of(context).pop();
You can use Positioned Widget in Stack Widget for Showing CircularProgressIndicator in front of all widgets like below..
Please put values according to your convenience in all four values bottom,left,right,top...
Positioned(
bottom: ,
left: ,
right: ,
top : ,
child: Container(
child : CircularProgressIndicator()
)
...
)
I removed Visiblity code with this one.
Old Code
Visibility(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
],
),
),
visible: visible,
),
New Code
visible ? Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child:SizedBox(// Center(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
),
)
: Container()
And most importantly it needs to call in the first Widget.
return Scaffold(
key: _scaffoldKey,
body: Stack(
children: <Widget>[
/////Some containers,child Widget etc/////////
visible ? Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child:SizedBox(// Center(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
),
)
: Container()
] //Widget
), //Stack
); //Scaffold
I am not sure i explained it properly or not. But Bottom line is it shouldn't be inside the other child widget.
It should be placed inside first children: <Widget>[ not inside the nested.
As above most of them gave answer to make separate reusable function. So here is mine if you want to fetch some data and display circular progress indicator while data is being fetched.
///Function to get data from a future and display a dialog with circlular progress indicator while data is fetched.
getFutureData(BuildContext context, var future) async {
var data;
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Center(
child: FutureBuilder(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
Navigator.pop(context);
}
return CircularProgressIndicator();
},
),
),
);
return data;
}

How did i setup popup AlertDialog?

How did i setup popup AlertDialog when int is equal or greater than 100?
showDialog(
context: _context,
builder: (BuildContext context) => AlertDialog(
title: Text("$_winner Won"),
)
);
void scoreTeamA() {
setState(() {
outputTeamA += _choiceA;
});
}
// I would like to show outputTeamA on the AlertDialog
Thank you
Mohammad
One way is to create a Widget for the AlertDialog and pass the String/Widget you want to show on that dialog.
class LoadingDialog{
static Future<void> showLoadingDialog(BuildContext context,String text) async {
return showDialog(
context: context,
builder: (BuildContext context){
return SimpleDialog(
children: <Widget>[
Center(
child: Container(
child: Column(
children: <Widget>[
SizedBox(
height:10,
),
Text(text),
]
),
),
),
],
),
}
);
}
}
then you can call on an Event like:
void scoreTeamA(){
outputTeamA += _choiceA;
LoadingDialog.showLoadingDialog(context, outputTeamA);
}
Note: this code might have some errors. i haven't tested this.
This is how I display an AlertDialog
showAlertDialog() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: BorderSide(color: Colors.redAccent, width: 2.0),
),
elevation: 6,
titlePadding: EdgeInsets.all(8.0),
titleTextStyle: TextStyle(
fontSize: 18, color: Colors.red, fontWeight: FontWeight.bold),
title: Text(
'This is the alert title',
textAlign: TextAlign.center,
),
contentPadding: EdgeInsets.all(8.0),
contentTextStyle: TextStyle(fontSize: 14, color: Colors.black),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Content...')
//content goes here
],
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(), child: Text('Okay'))
],
),
);
}
And then you would do your if check to check
if( outputTeamA >= 100){
showAlertDialog();
}
Of course you could use outputTeamA in AlertDialog

"Undefined name 'context'. Try correcting the name to one that is defined, or defining the name." Flutter

This is a snippet of my widgets.dart file where I defined a widget called see_all_cards and its only purpose is to show an extended list of all cards that I was initially displaying. It should just redirect to Trending.dart. That's my main goal here.
Widget see_all_cards(){
return Container(
child: FlatButton(
child: Text(
"See all (43)",
style: TextStyle(
color: Theme.of(context).accentColor, // error
),
),
onPressed: (){
Navigator.push(
context, // error
MaterialPageRoute(
builder: (BuildContext context){
return trending();
},
),
);
},
)
);
}
The following segment is my main page. I've called SlowlyApp from void main.
class SlowlyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SlowlyApp',
home: Scaffold(
appBar: AppBar(
title: Text('Search',
style: TextStyle(
color: Color.fromRGBO(0,0,0,1),
),
),
backgroundColor: Color.fromRGBO(225,225,0,1),
actions: <Widget>[
IconButton(
icon:
Icon(Icons.search),
onPressed: (){
showSearch(context: context, delegate: data_search());
}
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
smallgap(),
current_cards_heading(),
current_cards(),
see_all_cards(),
smallgap(),
],
),
),
);
}
}
see_all_cards should expect context as parameter. You only have context in your main widget's build method
Widget see_all_cards(BuildContext context){
return Container(
child: FlatButton(
child: Text(
"See all (43)",
style: TextStyle(
color: Theme.of(context).accentColor, // error
),
),
onPressed: (){
Navigator.push(
context, // error
MaterialPageRoute(
builder: (BuildContext context){
return trending();
},
),
);
},
)
);
}
And then you can call passing the context.
class SlowlyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SlowlyApp',
home: Scaffold(
appBar: AppBar(
title: Text('Search',
style: TextStyle(
color: Color.fromRGBO(0,0,0,1),
),
),
backgroundColor: Color.fromRGBO(225,225,0,1),
actions: <Widget>[
IconButton(
icon:
Icon(Icons.search),
onPressed: (){
showSearch(context: context, delegate: data_search());
}
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
smallgap(),
current_cards_heading(),
current_cards(),
see_all_cards(context),
smallgap(),
],
),
),
);
}
}
I also get this error to solve this way
it's the main file container called my widgets _buildFoodItem define context with parameters
Container(
height: MediaQuery.of(context).size.height - 185.0,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(75.0),
),
),
child: ListView(
primary: true,
padding: const EdgeInsets.only(left: 25.0, right: 20.0),
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 45.0),
child: Container(
height: MediaQuery.of(context).size.height - 300.0,
child: ListView(children: [
_buildFoodItem(context, 'assets/images/plate1.png',
'Slazmon bowl', '₹ 150:00'),
_buildFoodItem(context, 'assets/images/plate2.png',
'Spring bowl', '₹ 120:00'),
_buildFoodItem(context, 'assets/images/plate3.png',
'Chikz bowl', '₹ 100:00'),
_buildFoodItem(context, 'assets/images/plate4.png',
'Berry Bowl', '₹ 199:00'),
_buildFoodItem(context, 'assets/images/plate5.png',
'Greezy bowl', '₹ 170:00'),
]),
),
)
],
),
),
this is my widget _buildFoodItem check the context
Widget _buildFoodItem(
BuildContext context, String imgPath, String foodName, String price) {
return Padding(padding: const EdgeInsets.only(
top: 10.0, left: 10.0, right: 10.0),
child: InkWell(
onTap: () {
Navigator.push(
context,
(MaterialPageRoute(
builder: (context) => FoodDetailsPage(
heroTag: imgPath,
foodName: foodName,
foodPrice: price,
),
)));
},
))
}
)