Flutter how to retrieve value from button - flutter

new FlatButton(
child: new Text("933478476")
)
Here i created one button now i want to store the value of button in string.How to store the values from widget.

The FlatButton dosen't take any value and would not return either. What you could do is, pass a void callback that triggers your function that takes button click values as arguments.
Example:
//Define you function that takes click
void _onClick(String value) {
//do something
}
// Make you `FlatButton` like this
FlatButton(
onPressed: () => _onClick('12345678'), // a lambda void callback that calls your click function with value
child: Text('12345678'),
);
Hope that helped!

Related

Difference between myFunction, myFunction(), and myFunction.call() in Dart/Flutter

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

Flutter pop best practice

I have the following flow Screen 1 -> Screen 2 -> Dialog (in a separate widget).
Screen 2 displays a dialog (Close? Yes or No). If someone presses Yes, I would like to return to the Screen 1, if they press No, just close the dialog and return to Screen 2. What I currently do is when Yes is tapped, I do Navigator.pop(context) twice. Is this a good practice? Is there a way to pass the context of Screen 2 to my dialog widget so I can pop that one directly?
Personally, I think it would be better to pass the response from the dialog back to the page, and let the page handle the rest.
You can do this:
//I'm using a raised button just to call the alert as an example...
RaisedButton(
child: Text('Press me'),
//This part here is the important part
onPressed: () async {
//You can return anything when you use Navigator.pop
//In this case I'm returning a bool indicating if the page should close or not.
//You have to await this because it depends on user input.
bool shouldPopResult = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
//The content of your dialog
actions: <Widget>[
// The value you pass here in Navigator.of(context).pop
// is the value that will be stored in shouldPopResult,
// so if "Yes" is pressed, true will return...
// and if "No", false is returned.
FlatButton(
child: Text('Yes'),
onPressed: () => Navigator.of(context).pop(true),
),
FlatButton(
child: Text('No'),
onPressed: () => Navigator.of(context).pop(false),
)
],
),
);
// This is for if the user dismisses the dialog without pressing a button
// In that case shouldPopResult would be null, so I'm setting it to false.
// You can prevent the user from dismissing the dialog
// setting barrierDismissible to false in the showDialog method.
if (shouldPopResult == null) shouldPopResult = false;
// And finally with the dialog already dismissed, you can decide
// to go back or not.
if (shouldPopResult) Navigator.of(context).pop();
});
As usual you can extract the dialog as a Widget, or extract the function that handles the dialog response altogether or anything else.
You can see the example of returning data from a page in the flutter documentation here.

How do we pass or propagate data backwards through the Navigation stack in Flutter?

1.FlatButton(
onPressed: () async {
var typedName=await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return CityScreen();
},
),
);
print(typedName); //prints the value of cityName
}
2. FlatButton(
onPressed: () {
Navigator.pop(context, cityName);
},
The no.1 is coming from file loading_screen and no.2 is coming from city_screen. Can you anyone help me understand what is happening that when you pass a variable or anything in the pop? And when come that onPress method is still working because the the method Navigator.push has been already assigned to the variable but still that method Navigator.push is working when I pressed the button?Does that onPress doesn't care about the variable TypedName and just looks for the method Navigator.push?
If you use push method it will create the new screen over your current page and pop will remove last screen, you cannot pass name with both, you can check basics of navigation here, if you want to pass name to next page you should use something like pushnamed method and you can see the logic of passing name here. And for all methods you should check here.

Flutter: Send data back to specific list item

I am trying to send data to a specific list item on the screen.
The logic is that you click on the specific card in the list it opens a second screen with an input field (see images below). You then submit your input and it changes the value of that specific card on the first screen.
What is the best way to achieve this?
You can do it like this:
Instead of only pushing to another page, await for a return
final data = await Navigator.push(context,
MaterialPageRoute(builder: (context) => InputScreen()));
setState(()
myList.add(data); //do whatever you want with the return here
});
And in your InputScreen you do this:
Navigator.of(context).pop(data);
Also, if your user press the back button of their phone, it will return null, so you will need to handle that.
You can achieve this by doing the steps below:
1) In the onTap function of the card, await the result by adding the code below:
// on tap function of your card
onTap: () async {
// navigate to the second screen and wait for input user enters
final result = await Navigator.push(context
MaterialPageRoute(builder: (context) => SecondScreen()));
// call setstate to see your changes
setState(() {
// add the input to your list
myList.add(result);
);
},
1) In the onTap function of your submit button send back the result by adding the code below:
// ontap function of your submit button
onTap: () {
// value is what the user has inputted in the text field
Navigator.pop(context, value);
},

Flutter - set result to return when the user navigates back

When calling Navigator.pop() a result can be passed to the previous screen. Is there a way to set the result so that if the user navigates back on their own the result is still returned to the previous page?
I could pass an object to the second page and then modify it so that the first page can check it when the second page returns, but I'd rather use the result returned from the Navigator as it's more readable.
Overriding the back button's tap detector as I've seen suggested elsewhere is not an acceptable solution because the user may navigate back in some other way such as swiping or pressing the Android back button.
Yes, you can pass data between screens both ways.
While popping back, send the data you wish to send like this from the second screen
RaisedButton(
onPressed: () {
// The Nope button returns "data" as the result.
Navigator.pop(context, 'data');
},
child: Text('Nope!'),
);
And catch the result in the your first screen like this
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
source
For the other concern where the user is able to go back to the previous screen by pressing the back button, you can wrap your second screen with WillPopScope widget and provide the onWillPop callback. This will override the popping of the second screen and execute the callback where you can define the value you wish to return from the second screen.
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(), // or your widget
onWillPop: () {
return Future.delayed(Duration(microseconds: 0), () {
return Navigator.pop(context, "return-data");
});
},
);
}
Yes, this is possible, when navigating to Screen B from Screen A, make the onTap() functionasynchronous and await the result from Screen B.
Check the code below: It works perfectly:
On Screen A, put this code:
onTap: () async {
// receive the data you are sending from screen B here
final result = await Navigator.push( context);
},
On Screen B, put this code:
onTap: (){
// pass the data you want to use in screen A as the second paramter
Navigator.pop(context,number);
},
I hope this helps