Code will explain all:
class ResultOverlay extends StatefulWidget {
final bool _isCorrect;
VoidCallback _onTap;
ResultOverlay(this._isCorrect, this._onTap);
......
......
}
Its state class:
class ResultOverlayState extends State<ResultOverlay>{
#override
Widget build(BuildContext context) {
........
child: new InkWell(
onTap: () => widget._onTap,
.....
.....
}
Passing of callback function:
new ResultOverlay(isCorrect, () {
() => CallAnswerPage();
})
What I am missing here?
This is a more general answer for future viewers.
Callback types
There are a few different types of predefined callbacks:
final VoidCallback myVoidCallback = () {};
final ValueGetter<int> myValueGetter = () => 42;
final ValueSetter<int> myValueSetter = (value) {};
final ValueChanged<int> myValueSetter = (value) {};
Notes:
VoidCallback is an anonymous function that takes no arguments and returns no value.
ValueGetter is an anonymous function that returns a value, which you provide for someone who wants to get it.
ValueSetter is an anonymous function that takes a value as an argument, which you can use to set some other value.
ValueChanged has the same function signature and is used the same way as ValueSetter, but its name emphasizes that the given value actually changed (and was not just set with the same value again).
See this answer for more details.
Ways to write the callback
Good
When you are asked to provide a callback to an API, you can directly write the callback:
onPressed: () {},
Or you can supply the callback variable name (without parentheses):
onPressed: myVoidCallback,
Less good
It would be unnecessarily verbose to use both forms (but you could if you included the parentheses after the variable name):
onPressed: () {
myVoidCallback();
},
This one is equivalent (but also unnecessarily verbose):
onPressed: () => myVoidCallback(),
Just use one of the "Good" forms from above.
Still good
The exception would be if you wanted to do something like call a value setter when the parameter is only asking for a void callback:
onPressed: () => myValueSetter(42),
I was not passing the callback correctly. Here is the correct syntax:
new ResultOverlay(
isCorrect,
() => callAnswerPage()
)
So silly mistake :)
Everything is fine beside how you use it.
Change
onTap: () => widget._onTap,
to
onTap: widget._onTap,
inside your State class
Related
I've noticed that when I have a widget/class that takes Functions as arguments, when it comes time to call those functions, it can be done one of three ways (that I know of):
(Consider a Function, myFunction)
myFunction
myFunction()
myFunction.call()
But the weird thing is, I've noticed that when using option 1), it will (ONLY SOMETIMES) not work and require the use of option 2 or 3 in order to work.
Why is that?
Specific example (I've verified the inconsistent calling behaviour with print debugging in the parent):
class SoundPickerTile extends StatelessWidget {
final Sound sound;
final Function() checkboxCallback;
final Function() soundPlayCallback;
SoundPickerTile(
{required this.sound, required this.checkboxCallback, required this.soundPlayCallback});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: checkboxCallback, // <--------------- Function executes in parent
child: Container(
color: sound.isIncluded ? Colors.lightGreen.withAlpha(100) : Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(20, 10, 0, 10),
child: Row(
children: [
Expanded(
child: Text(
sound.shortTitle,
),
),
Expanded(
child: IconButton(
icon: Icon(Icons.play_circle_outline),
onPressed: () {
print("this line of code was reached"); // this works
soundPlayCallback; // <--------------- Function *does not* execute in parent
},
),
),
],
),
),
),
);
}
}
They are all the same object, but with two different behaviours.
myFunction is your function but shaped like an object. So you can pas this around as an argument for onTap (which takes a function like that as argument). That's also why it's run in the parent, that's how it's supposed to work. It gets tossed around as an object and the parent calls () on it.
The reason it's not being executed below is because there you are simple putting the function down as an object. Much like you earlier passed it as an object, right now you're just saying hey here's the function, but I'm not gonna do anything with it.
myFunction; -> no ()
So in order for it to work you need to use number 2. or 3.
myFunction() -> This will call your object (your function) and run it's code, contrary to the previous mentioned example where you just lay the object down. The () is important!
Now the difference between 2. and 3. is.. almost nothing!
() actually does the .call() in the background, however if you have a myFunction that's possibly null, then you can do something like this:
myFunction?.call();
This will only call the function if it's not null, else it will not do anything.
Hope that's clear, also try to define a return value when specifying callbacks, this will make you understand passing around functions quicker. And have a look at typedefs, they are basically signatures for specific functions (VoidCallback for example). Once you grasp that concept passing around functions will become a breeze! Goodluck.
Let's examine these cases and understand what they are:
myFunction:
This one is just a reference to a function. When you write this, the function is not called. Instead, we may be giving the function to somebody else, who may or may not call it in the future.
myFunction() and
myFunction.call():
Call the function. When you write this, the function executes, whatever side effects it has happen and it returns whatever it returns.
So 2 and 3 are exactly the same. So let's focus on the difference between 1 and 2. That is, myFunction and myFunction().
myFunction is a reference to a function. Kind of like the i in int i = 5. You can call it by adding () at the end, or calling its .call() method. Similarly, you can do i.isEven with i.
Example: I'm calling the function. Whatever side effects it has will happen before the next line.
myFunction();
myFunction.call(); // same thing
Alternative to calling myFunction, you can also pass it around as a reference to a function. This is like passing around an int. You are passing the reference to this function to some other place in your code. It may or may not be called in the future. You can call it, you can throw it away, it's your call.
Example: Dear button, here's a function. Call it when you're pressed.
Button(
onPressed: myFunction,
)
Example: Dear button, here's a little function (the () =>) that returns a reference to myFunction. When button calls this, it receives the reference to myFunction. However, the button just calls what you give to onPressed. It does not care about what you return from that. Therefore, you return the reference myFunction but it is never called, it's thrown away.
Button(
onPressed: () => myFunction,
onPressed: () {return myFunction;} // same thing
)
Example: Dear button, here's a little function that calls myFunction() and returns whatever it returns. So myFunction is actually called when the button is pressed.
Button(
onPressed: () => myFunction(),
)
Example: Dear button, here's a little function that does not return anything. One of its lines is myFunction;, which does not do anything, it's like writing 1;, nothing is done with it. Therefore myFunction is not called.
Button(
onPressed: () { myFunction; }
)
Any possible usage of myFunction should fall into one of these categories. The descriptions of the examples should help in understanding what that usage means.
In the GestureDetector we use:
onTap: checkboxCallback,
without the (), since that would call the function immediately, we don't want to call the function, we just want to pass a reference to the function on what should happen when onTap is called.
Then with:
onPressed: () {
print("this line of code was reached"); // this works
soundPlayCallback; // <--------------- Function *does not* execute in parent
},
Since were are not using () it's not being called it's just a reference to the function.
Instead, what you can do is:
onPressed: soundPlayCallback;
Or add the ()
Edit.
What is the difference between calling the function without parentheses and with parentheses
I want to be able to pass a future as an argument in a class constructor to be used later. Here's the code of the class to help explain...
class Custom extends StatelessWidget {
final String title;
final Future action; //trying to pass a future to be called later
Custom({#required this.title, #required this.action});
#override
Widget build(BuildContext context) {
...
return Column(
children: <Widget> [
Text(title),
RaisedButton(
...
onPressed: () {
action;
}
),
],
),
}
So when I try to build
Custom(title: "print something", action: doSomething())
..what ends up happening is doSomething runs immediately instead of when I press the RaisedButton. If I remove the () at the end of doSomething, I get the error:
The argument type 'Future<dynamic> Function()' can't be assigned to the parameter type 'Future<dynamic>'.
Do I need to do something different in the class constructor? Or if this is not possible, is there a way to achieve this differently?
EDIT:
Based on early answers, I changed my constructor to
final Future Function() action;
Now it builds, but it's still not calling it. I tried creating the future I'm trying to call in both the Custom class and in the class I'm building Custom from, but neither work. Ideally, I'd like to have the Future I'm calling in the class I'm building from. Any suggestions?
EDIT:
This is working now. It wasn't working because besides my changes above, I also had to change onPressed: action()
Try changing the declaration to
final Future Function() action;
And use it without the ()
Custom(title: "print something", action: doSomething)
The error you're seeing is pretty spot on in description. The Future<?> Function() and Future<?> are unrelated types. All the functions you write that you wrap with Future<?> functionName() async are returning an instance of Future but by themselves have nothing to do with Futures, so reference to that function can't be used as a parameter that expects Future type.
Additionally, you need to figure out what to do with generic parameter for the Future data type. If you leave it as Future (which is the same as Future<dynamic> you'll never get compiler errors when forwarding any Future<?> type there but while you won't get any compile errors you can get into runtime issues if the expected output type of that Future turns to be something other than the type you're expecting.
If you're only calling Future<void> method you can simply put Future<void> Function() action; as your field type. If you're going to be calling different data types but only ever calling the same data type on the same instance of Custom widget you can make it generic as well, like this:
class Custom<T> extends StatelessWidget {
final String title;
final Future<T> Function() action;
Custom({#required this.title, #required this.action});
//...
}
I was playing around with functions and tried to create a new widget:
newWidget(Function onTap){
return InkWell(
...
onTap: () => onTap
);
}
When tried to use it, I found that giving the onTap as onTap: () => onTap, and using it as onTap: () => onTap(), performed differently. And there's other ways to use the onTap property.
So what's the difference between:
onTap: () => onTap
onTap: () => onTap()
onTap: onTap()
onTap: () => func
This one point the widget to func function and tells it run it when tapped. Like you give it the address of the function and tell it to go there in case someone taps.
onTap: () => func()
onTap: func()
These two basically do the same thing and give onTap property the value returned from the func(). These ones however, takes onTap to the address instead of pointing it to it. These will run immediately after build completes.
You can simply call onTap: func if you don't have to pass it any parameters.
Otherwise call onTap: (param1, param2, ...) => func(param1, param2, ...)
You can also use it like:
onTap: funcationName //with out brackets
How can I pass multiple rows of data from one screen to the second one without overloading the values of the first data passed?
onPressed: () {
setState(() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => new orderpage(
'${widget.productName.toString()}',
'$total',
counter,
check_tandeef,
check_makwa,
sab8a)));
I think I understood your point, I'm not sure.
To pass values, you can use args in the Navigator and the use those values in your second screen.
https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments
Another way, would be using InheritedWidget class, so you can use the same instance of an object all across your widgets without being passing them by the context
https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
I am assuming you mean you wan't to pass multiple sets of the same data to the next screen. You could do this by creating a class which holds all your params, and then pass a list to your Screen.
class myViewModel{
String param1;
String param2;
int param3;
bool param4;
myViewModel(this.param1,this.param2,this.param3,this.param4);
}
Create the list and fill it with instances of the Class:
listOfParams = List<myViewModel>();
Pass the List:
onPressed: () {
setState(() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => new orderpage(
listOfParams
)));
What is the difference for these two variants? If the function _getCsvDocunent is just void type then what does it mean if we define onPressed like onPressed: () => _getCsvDocunent(), ?
FlatButton(
child: Text('Provide .csv data file'),
onPressed: _getCsvDocunent,
),
vs
FlatButton(
child: Text('Provide .csv data file'),
onPressed: () => _getCsvDocunent(),
),
In onPressed:_getCsvDocunent: onPressed gets an reference to _getCsvDocument passed to it. This way of passing a reference is only possible when the function to be passed is already defined and is compatible with onPressed.
In onPressed: () => _getCsvDocunent(): onPressed gets the value returned by
_getCsvDocunent after it is done executing.
In onPressed: () => _getCsvDocunent(): onPressed gets a reference to _getCsvDocument exactly similar to the case in the first bullet point, difference being, in this case a function reference (_getCsvDocument) is directly passed to onPressed instead of using an inline function to return a reference to _getCsvDocument.