I put a list of widget as action in Scaffold appBar, but they didn't respond when I press them, I have a floatingButton in the scene too and it works perfectly.
appBar: new AppBar(
title: new Text(
widget.title,
style: new TextStyle(
fontFamily: 'vazir'
),
),
centerTitle: true,
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.search),
highlightColor: Colors.pink,
onPressed: _onSearchButtonPressed(),
),
],
),
void _onSearchButtonPressed() {
print("search button clicked");
}
even if I put IconButton in a Row or Column widget , not in appBar, it doesn't work again.
Answer:
thanks to siva Kumar, I had a mistake in calling function , we should call it in this way:
onPressed: _onSearchButtonPressed, // without parenthesis.
or this way:
onPressed: (){
_onSearchButtonPressed();
},
please try with my answer it will work.
appBar: new AppBar(
title: new Text(
widget.title,
style: new TextStyle(
fontFamily: 'vazir'
),
),
centerTitle: true,
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.search),
highlightColor: Colors.pink,
onPressed: (){_onSearchButtonPressed();},
),
],
),
void _onSearchButtonPressed() {
print("search button clicked");
}
Bump into the question while searching for other solution.
The answer should be:
onPressed: _onSearchButtonPressed,
Without the () brackets. Since they carry the same signature, there is no need to wrap them around another anonymous / lambda function.
Actually we need to set the VoidCallback for onPressed property, When we tap on icon that VoidCallback is called .
We also set null if we don't need any response.
class PracticeApp extends StatelessWidget {
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton: new FloatingActionButton(
tooltip: "Add",
child: new Icon(Icons.add),
onPressed: () { setState(); },
),
);
}
}
void setState() {
print("Button Press");
}
We can also directly pass the call back like this
onPressed: () { setState(() { _volume *= 1.1; }); }
Example for null
onPressed: null
Related
I'm stuck with making a scrollable list like Google Task app when you reach end of the list if any task is completed it shown in another list with custom header as you can see here, I'm using sliver
Widget showTaskList() {
final todos = Hive.box('todos');
return ValueListenableBuilder(
valueListenable: Hive.box('todos').listenable(),
builder: (context, todoData, _) {
int dataLen = todos.length;
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
floating: true,
expandedHeight: 100,
flexibleSpace: Container(
padding: EdgeInsets.only(
left: MediaQuery.of(context).size.width / 10,
top: MediaQuery.of(context).size.height / 17),
height: 100,
color: Colors.white,
child: Text(
'My Task',
style: TextStyle(fontSize: 30.0, fontWeight: FontWeight.w600),
),
),
),
SliverList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index) {
final todoData = todos.getAt(index);
Map todoJson = jsonDecode(todoData);
final data = Todo.fromJson(todoJson);
return MaterialButton(
padding: EdgeInsets.zero,
onPressed: () {},
child: Container(
color: Colors.white,
child: ListTile(
leading: IconButton(
icon: data.done
? Icon(
Icons.done,
color: Colors.red,
)
: Icon(
Icons.done,
),
onPressed: () {
final todoData = Todo(
details: data.details,
title: data.title,
done: data.done ? false : true);
updataTodo(todoData, index);
}),
title: Text(
data.title,
style: TextStyle(
decoration: data.done
? TextDecoration.lineThrough
: TextDecoration.none),
),
subtitle: Text(data.details),
trailing: IconButton(
icon: Icon(Icons.delete_forever),
onPressed: () {
todos.deleteAt(index);
}),
),
),
);
}, childCount: dataLen),
),
],
);
});
}
ShowTaskList is called on
Scaffold(
body: SafeArea(
child: Column(children: <Widget>[
Expanded(
child: showTaskList()
),
]),
),
I tried OffStageSliver to make an widget disappear if no complete todo is present but that did not work and also can not use any other widget on CustomScrollView because that conflict with viewport because it only accept slivers widget.
Here what i have achieved so far
You can try use ScrollController put it on CustomScrollView and listen to it's controller in initState like this :
#override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
// If it reach end do something here...
}
});
}
I suggest you make bool variable to show your widget, initialize it with false and then after it reach end of controller call setState and make your variable true, which you can't call setState in initState so you have to make another function to make it work like this:
reachEnd() {
setState(() {
end = true;
});
}
Put that function in initState. And make condition based on your bool variabel in your widget
if(end) _yourWidget()
Just like that. I hope you can understand and hopefully this is working the way you want.
So my question is: Is it posible to run function from state in other script?
E.g:
I have 2 scripts, lets say i have main.dart and loadingScreen.dart
main.dart
//...
OutlineButton(
child: Text("Status", style: TextStyle(color: Colors.white, fontSize: 17), textAlign: TextAlign.center,),
borderSide: BorderSide(color: Colors.grey[400]),
onPressed: () async {
Navigator.pushNamed(context, '/loadingScreen', arguments: {"text": "Checking\nstatus"});
//...
// <--- Here I want to run updateLoadingText from loadingScreen.dart
Navigator.pop(context);
}
),
//...
loadingScreen.dart
class _LoadingScreenState extends State<LoadingScreen> {
Map data = {};
String loadingText;
updateLoadingText(newText){
//...
}
#override
Widget build(BuildContext context) {
//...
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
backgroundColor: Colors.grey[800],
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SpinKitCubeGrid(
color: Colors.white,
size: 80,
),
SizedBox(height: 24,),
Text(
loadingText,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 35,
),
)
],
),
)
),
);
}
}
Is it possible to run updateLoadingText in main.dart?
Thx for help!
You can do this by passing a key to the widget and then using the key to access the widget's state. (You will need to make the state class public to do this.)
main.dart
// In the class fields
final loadingScreenKey = GlobalKey<LoadingScreenState>();
// Where you build LoadingScreen
LoadingScreen(
key: loadingScreenKey,
// ...
),
// Button code
OutlineButton(
// ...
onPressed: () async {
// ...
loadingScreenKey.currentState.updateLoadingText(...),
},
),
DISCLAIMER
Calling a state method from another widget directly like this is generally considered bad form since this will produce highly coupled and decentralized spaghetti code. As such, you should instead look into a system where you notify the widget to change via an impartial service. There are a lot of ways to do this, such as with an event bus, a ChangeNotifier, or with a state management library like provider or flutter_bloc.
I am trying to create a simple To Do App in in flutter with a Floating Action Button in the bottom which when clicked show an Alert Dialog to add items to the list.
Every time I click on the button, the Keyboard pushes the Action Button upward causing overflowing error.
Is there any way to avoid pushing the action button upward when Keyboard is opened?
Here is the snapshot I took:
Snapshot
Below the source code:
import 'package:flutter/material.dart';
import '../model/todo_item.dart';
class ToDoScreen extends StatefulWidget {
#override
_ToDoScreenState createState() => _ToDoScreenState();
}
class _ToDoScreenState extends State<ToDoScreen> {
TextEditingController _textEditingController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueAccent,
body: Column(
children: <Widget>[ToDoItem("Going for a Walk", "12 January, 2019")],
),
floatingActionButton: FloatingActionButton(
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.red,
onPressed: _showFormDialog,
),
);
}
void _showFormDialog() {
var alert = AlertDialog(
content: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
decoration: InputDecoration(
labelText: "Item",
hintText: "eg. Buy Vegetables",
icon: Icon(Icons.note_add)),
),
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () {
// _handleSubmit(_textEditingController.text);
_textEditingController.clear();
},
child: Text("Save ToDo"),
),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Cancel"),
)
],
);
showDialog(context: context, builder: (BuildContext context) => alert);
}
}
I had the same issue, where my Floating Action Button would get pushed up.
I solved this using the property:
resizeToAvoidBottomPadding: false, // fluter 1.x
resizeToAvoidBottomInset: false // fluter 2.x
On the parent Scaffold.
I tested it with your code, it solves the issue as well.
You can check if the keyboard is show up or not, and based on that create the floating button or not.
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: keyboardIsOpened ?
null ://or an empty container
FloatingActionButton(
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.red,
onPressed: _showFormDialog,
),
);
}
Inside the build method you can know if the keyboard show up by using MediaQuery.of(context).viewInsets.bottom and save its value on a bool variable keyboardIsOpened like the following code.
#override
Widget build(BuildContext context) {
bool keyboardIsOpened = MediaQuery.of(context).viewInsets.bottom != 0.0;
Used MediaQuery and Visibility
Visibility(
visible: MediaQuery.of(context).viewInsets.bottom == 0.0,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.chat),
),
),
When the keyboard is opened, the bottom will not be zero, which will cause fab to get invisible.
Wrap your complete code in this
new Container(
child: Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Stack(
children: <Widget>[
// Your body code
] // Widget
), // Stack
), // SingleChildScrollView
), // Expanded
Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.all(10.0),
child :
// button code here
// to make button full width use minWidth: double.infinity,
,
), //Container
], // Widget
), // Column
), // Container
Wrapping the Floating Action Button inside a column together with my bottom navigation, then passing this as the child to my bottom navigation bar solved most of the stated concerns: Also ensure you add mainAxisSize: MainAxisSize.min,to your column.
i try this so good
Visibility(
visible: MediaQuery.of(context).viewInsets.bottom == 0.0,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.chat),
),
),
I have a strange problem with AlertDialog in flutter to dismiss the dialog. I was using the below code snippet to close the dialog as mentioned in the flutter documentation.
Navigator.of(dialogContext).pop();
But show how it doesn`t work and make the app into the inactive mode and turns into the black screen window. To make it work again, i have to kill the app and restart again.
Here is the complete code for alertdialog in flutter
Future<Null> _showDialogContactDial(context, Contact contactRecord) async {
return showDialog<Null>(
context: context,
barrierDismissible: true, // user must tap button!
builder: (BuildContext dialogContext) {
return new AlertDialog(
title: new Text('Confirm Number'),
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
new TextFormField(
maxLines: 1,
decoration: new InputDecoration(hintText: 'Number'),
keyboardType: TextInputType.number,
autofocus: false,
initialValue: contactRecord.phoneNumber.number,
),
],
),
),
actions: <Widget>[
new FlatButton(
child: new Text(
'Call',
style: TextStyle(color: Colors.black),
),
onPressed: () {
Navigator.of(dialogContext).pop();
_launchURL(
context);
},
),
new FlatButton(
color: Colors.red,
child: new Text('Close', style: TextStyle(color: Colors.white)),
onPressed: () {
Navigator.of(dialogContext).pop();
},
),
],
);
},
);
}
I also noticed that it works for one button "call" without any issues but not for the cancel alert dialog as you see in the same code snippet in both button actions.
Help would be appreciated.
Just add rootNavigator:true
Navigator.of(dialogcon, rootNavigator: true).pop();
This worked in my application , i have made little changes in your code ,hope this might help , if this doesn't help you then I think here is a problem in _launchURl method.
void _showDialogContactDial(BuildContext context, Contact contactRecord){
showDialog<Null>(
context: context,
barrierDismissible: true, // user must tap button!
builder: (BuildContext dialogContext) {
return new AlertDialog(
title: new Text('Confirm Number'),
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
new TextFormField(
maxLines: 1,
decoration: new InputDecoration(hintText: 'Number'),
keyboardType: TextInputType.number,
autofocus: false,
initialValue: contactRecord.phoneNumber.number,
),
],
),
),
actions: <Widget>[
new FlatButton(
child: new Text(
'Call',
style: TextStyle(color: Colors.black),
),
onPressed: () {
Navigator.of(dialogContext).pop();
_launchURL(
context);
},
),
new FlatButton(
color: Colors.red,
child: new Text('Close', style: TextStyle(color: Colors.white)),
onPressed: () {
Navigator.of(dialogContext).pop();
},
),
],
);
},
);
}
Use this method as a callback for onTap or wherever you are using it.
Inside your dialog. Surround your flatbuttons with Builder.
Builder(
builder: (context) => FlatButton(
child: Text('Cancelar'),
onPressed: () {
Navigator.of(context).pop();
},
),
),
I have the following AlertDialog.
showDialog(
context: context,
child: new AlertDialog(
title: const Text("Location disabled"),
content: const Text(
"""
Location is disabled on this device. Please enable it and try again.
"""),
actions: [
new FlatButton(
child: const Text("Ok"),
onPressed: _dismissDialog,
),
],
),
);
How can I make _dismissDialog() dismiss said AlertDialog?
Navigator.pop() should do the trick. You can also use that to return the result of the dialog (if it presented the user with choices)
Navigator.of(context, rootNavigator: true).pop('dialog')
worked with me.
Navigator.pop(_)
worked for me, but the Flutter Team's gallery contains an example using:
Navigator.of(context, rootNavigator: true).pop()
which also works, and I am tempted to follow their lead.
If you don't want to return any result, use either of them:
Navigator.of(context).pop();
Navigator.pop(context);
But if you do want to return some result, see this
Example:
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('Wanna Exit?'),
actions: [
FlatButton(
onPressed: () => Navigator.pop(context, false), // passing false
child: Text('No'),
),
FlatButton(
onPressed: () => Navigator.pop(context, true), // passing true
child: Text('Yes'),
),
],
);
}).then((exit) {
if (exit == null) return;
if (exit) {
// user pressed Yes button
} else {
// user pressed No button
}
});
Generally Navigator.pop(context); works.
But If the application has multiple Navigator objects and dialogBox doesn't close, then try this
Navigator.of(context, rootNavigator: true).pop();
If you want to pass the result call, try
Navigator.pop(context,result);
OR
Navigator.of(context, rootNavigator: true).pop(result);
Navigator.of(dialogContext).pop() otherwise you can close page if you navigated from Master to Detail page
showDialog(
context: context,
builder: (dialogContext) {
return Dialog(
child: Column(
children: [
Text("Content"),
RaisedButton(
onPressed: () => Navigator.of(dialogContext).pop(),
child: Text("Close"),
)
],
),
);
},
);
Example of dismissing alert dialog on flat button click
RaisedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Are you sure?'),
content: Text('Do you want to remove item?'),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(false),// We can return any object from here
child: Text('NO')),
FlatButton(
onPressed: () => Navigator.of(context).pop(true), // We can return any object from here
child: Text('YES'))
],
)).then((value) =>
print('Selected Alert Option: ' + value.toString()));
},
child: Text('Show Alert Dialog'),
),
Above code have two unique things which is used to provide callback result of dialog
Navigator.of(context).pop(false) -- return false value when we pressed
NO Navigator.of(context).pop(true) -- return true value when we
pressed YES
Based on these return value, we can perform some operation outside of it or maintain the dialog status value
This works Prefectly
RaisedButton(
child: Text(
"Cancel",
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () => Navigator.pop(context),
),
This worked for me Navigator.of(context, rootNavigator: true).pop('dialog').
Navigator.pop() just closes the current page/screen.
Creating a separate context for Alert Dialog would help.
showDialog(
context: context,
builder: (alertContext) => AlertDialog(
title: const Text("Location disabled"),
content: const Text(
"""Location is disabled on this device. Please enable it and try again."""),
actions: [
new FlatButton(
child: const Text("Ok"),
onPressed: () => Navigator.pop(alertContext),
),
],
),
);
Please use following for code to close dialog
RaisedButton(
onPressed: () { Navigator.of(context).pop();},
child: Text("Close",style: TextStyle(color: Colors.white), ),
color: Colors.black,
)
Use Navigator.pop(context);
Example
showDialog(
context: context,
child: new AlertDialog(
title: const Text("Location disabled"),
content: const Text(
"""
Location is disabled on this device. Please enable it and try again.
"""),
actions: [
new FlatButton(
child: const Text("Ok"),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
This answer works if you want to pop the dialog and navigate to another view. This part 'current_user_location' is the string the router need to know which view to navigate to.
FlatButton(
child: Text('NO'),
onPressed: () {
Navigator.popAndPushNamed(context, 'current_user_location');
},
),
This enough to dismisss dialog add inside Any callback like onpressed,ontap
Navigator.of(context).pop();
AlertDialog(
title: Center(child: Text("$title")),
insetPadding: EdgeInsets.zero,
titlePadding: EdgeInsets.only(top: 14.0, bottom: 4),
content: Container(
height: 50,
child: TextFormField(
controller: find_controller,
decoration: InputDecoration(
suffixIcon: context.watch<MediaProvider>().isChangeDialog
? IconButton(
onPressed: () {
clearController(find_controller);
},
icon: Icon(Icons.clear))
: null,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.deepPurpleAccent)),
hintText: 'Id',
),
onChanged: (val) {
if (val.isNotEmpty)
context.read<MediaProvider>().isChangeDialog = true;
else
context.read<MediaProvider>().isChangeDialog = false;
},
),
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: OutlinedButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Icon(Icons.clear),
),
),
Text("Cancel")
],
),
onPressed: () {
context.read<MediaProvider>().isChangeDialog = false;
//========================this enough to dismisss dialog
Navigator.of(context).pop();
}),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: ElevatedButton(
onPressed: context.watch<MediaProvider>().isChangeDialog
? () {
context.read<MediaProvider>().isChangeDialog = false;
okCallback;
}
: null,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Icon(Icons.check),
),
),
Text("OK")
],
)),
)
],
),
],
);
pass it in the showDialog
barrierDismissible : true
use get package.
then Get.back() to close Modal
For Closing Dialog
void cancelClick() {
Navigator.pop(context);
}
The accepted answer states how to dismiss a dialog using the Navigator Class. To dismiss a dialog without using Navigator you can set the onPressed event of the button to the following:
setState((){
thisAlertDialog = null;
});
In case the code above is not self-explanatory it is basically setting the Parent AlertDialog of the FlatButton to null, thus dismissing it.