Flutter : PopUp Form value showing null - flutter

Iam new to flutter.
In my project I need to show a popup when i load my page. So i used WidgetsBindingin initstate().
My code is working fine for showing popup on pageload, but in that popup,there is a textfield to enter mobile number after submitting i need to get that phone number but it not showing the value. While compiling it showing null value.
#override
void initState() {
super.initState();
// _fetchSessionAndNavigate();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await showDialog<String>(
context: context,
builder: (BuildContext context) => new AlertDialog(
content: Stack(
overflow: Overflow.visible,
children: <Widget>[
Positioned(
right: -40.0,
top: -40.0,
child: InkResponse(
onTap: () {
Navigator.of(context).pop();
},
child: CircleAvatar(
child: Icon(Icons.close),
backgroundColor: Colors.red,
),
),
),
Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
keyboardType: TextInputType.number,
maxLines: 1,
obscureText: true,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Enter Mobile Number',
icon: new Icon(
Icons.phone_iphone,
color: Colors.grey,
)),
validator: (value) => value.isEmpty
? 'Phone Number can\'t be empty'
: null,
onSaved: (value) => phoneNumber = value.trim();
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text("Register Your Device"),
onPressed: () {
if (_formKey.currentState.validate()) {
//_formKey.currentState.save();
Print (_phoneNumber); //NEED TO GET ENTERED VALUE HERE
}
},
),
)
],
),
),
],
),
),
);
});
}

You can remove the await keyword from in front of the function and call it like this:
showDialog({the dialog}).then((dialogResult){
setState((){
yourLocalVariable = dialogResult;
});
});

Related

set selected to radio button Flutter

How to set radio button to selected based on String value fetched from API?
I have an async function that does the API call and fetches the user profile. I need to set the selected gender to the radio button.
I tried calling SetState() from an async function but it results in infinite loop call for build().
Below is my code:
#override
Widget build(BuildContext context) {
if(isProfileExists) {
getProfileDetails();
print("selected radio : "+selectedRadio.toString());
if(selectedRadio >= 0) {
setMemberType(selectedRadio);
}
}
double width=MediaQuery.of(context).size.width;
double height=MediaQuery.of(context).size.height;
Future<bool> _onWillPop() async {
Navigator.pushNamedAndRemoveUntil(context, '/home', ModalRoute.withName('/home'));
}
return new WillPopScope(
child: Scaffold(
appBar: AppBar(
title: Text(
_userName+"\'s Profile ",
style: TextStyle(fontSize: 20.0),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.save
),
)
),
],
),
key: _scaffoldKey,
body: Container(
height: height,
width: width,
child: SingleChildScrollView(
padding: EdgeInsets.fromLTRB(0, 20.0, 0, 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
onTap: (){},
child: TextField(
decoration: InputDecoration(labelText: "Bio"),
controller: bioTextController,
),
),
SizedBox(height: 20.0,),
Padding(
padding: EdgeInsets.all(10.0),
child: Text("Basic Information", style: TextStyle(
color: Colors.black54,
fontSize: 14.0
),
),
),
TextField(
decoration: InputDecoration(labelText: "Height"),
controller: heightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Weight"),
controller: weightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "BMI"),
controller: bmiTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Target Weight"),
controller: targetWeightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Date Of Birth"),
controller: dateOfBirthController,
),
TextFormField(
decoration: InputDecoration(labelText: "Age"),
readOnly: true,
controller: ageTextController,
),
SizedBox(height: 15.0),
Text("Gender"),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Radio(
value: 0,
groupValue: radioValue,
onChanged: setMemberType,
),
Text("Female" ),
Radio(
value: 1,
groupValue: radioValue,
onChanged: setMemberType,
),
Text("Male"),
],
),
...
And the set state function is below:
void setMemberType(int i) {
setState(() {
radioValue = i;
if(i == 0)
_gender = "F";
else
_gender = "M";
});
}
You cannnot call setState from your build method.
Remove this:
if(isProfileExists) {
getProfileDetails();
print("selected radio : "+selectedRadio.toString());
if(selectedRadio >= 0) {
setMemberType(selectedRadio);
}
}
Instead, use an initState inside the State of your Stateful Widget:
#override
void initState() {
if(isProfileExists) {
getProfileDetails();
if(selectedRadio >= 0) {
radioValue = selectedRadio;
}
}
}

Flutter: Create custom dialog as StatefulWidget?

I'm working on an app that will get only 2 inputs from the user, maybe 3 in the future. So I use showDialog with 2 inputfield and 2 buttons. Very simple. Looks pretty much like this:
enter image description here
It shows up perfectly in the main screen if it's being called as a function. But I would like to use that same dialog in another screen in the app and just change the text on one of the buttons. Since the dialog code it's long and I don't want to repeat it, I want to put it in a new StatefulWidget (to retrieve the information from the input fields and clear them afterwards). Now the problem is that I can't find a way to return the dialog from an external widget. I don't know if it's actually impossible because of the whole async Widget incompatibility or I'm just too stupid to figure this out.
This is the code for my dialog (as a function):
_dialog() async {
await showDialog<String>(
context: context,
child: ButtonBarTheme(
data: ButtonBarThemeData(alignment: MainAxisAlignment.center),
child: AlertDialog(
contentPadding: const EdgeInsets.all(20.0),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.only(bottom: 15),
child: new TextField(
// onSubmitted: next,
autofocus: true,
controller: _title,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 2),
labelText: 'Title',
hintText: 'Example: New Smartphone',
),
),
),
TextField(
autofocus: true,
controller: _codigo,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
labelText: 'Code',
hintText: 'Example: EC20008347607',
),
),
],
),
actions: [
Row(
children: [
Container(
padding: EdgeInsets.only(right: 35, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('CANCEL'),
onPressed: () {
Navigator.pop(context);
}),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('ADD'),
onPressed: () {
setState(() {
_title.text = '';
_code.text = '';
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
);
}
Thanks in advance for any help. I'm a beginner.
You can put it in another dart file that accepts any property values that aren't static, like this:
CustomAlertDialog({String leftButtonText, String rightButtonText}) async {
return AlertDialog(
contentPadding: const EdgeInsets.all(20.0),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.only(bottom: 15),
child: new TextField(
// onSubmitted: next,
autofocus: true,
controller: _title,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 2),
labelText: 'Title',
hintText: 'Example: New Smartphone',
),
),
),
TextField(
autofocus: true,
controller: _codigo,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
labelText: 'Code',
hintText: 'Example: EC20008347607',
),
),
],
),
actions: [
Row(
children: [
Container(
padding: EdgeInsets.only(right: 35, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('$leftButtonText'),
onPressed: () {
Navigator.pop(context);
}),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 5),
child: FlatButton(
color: Colors.cyan[600],
child: const Text('$rightButtonText'),
onPressed: () {
setState(() {
_title.text = '';
_code.text = '';
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
);
}
I think we have to build our widget from the ground up as there is no dialog box that exposes the state. Hope this helps:
https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html
Try my code snippet
**
MaterialButton(
color: Colors.blue,
height: 50,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
textColor: Colors.white,
child: Text('Show Info Dialog',),
onPressed: () {
SimpleDialogs.showinfoDialog(context: context, title: "Something insert here");
},

Using Visibility Widget in Flutter to toggle widgets display

I have a Column widget I'd only like to make visible when a user taps on the add new button. I am using the Visibility widget Flutter provides and I am using setState() to change the visible property in the Visibility widget class. It doesn't work.
What could I be overlooking? Find my code snippet below:
bool _addNewTax = false;
FlatButton.icon(
color: kBgCircleColour,
padding: EdgeInsets.all(15.0),
icon: Icon(
FontAwesomeIcons.plusSquare,
color: kThemeStyleButtonFillColour,
),
onPressed: () {
setState(() {
_addNewTax = true;
});
Visibility(
visible: _addNewTax,
child: _buildTaxInputFields(),
);
},
label: Text(
'Add new tax',
style: kRegularTextStyle,
),
);
My _buildTaxInputFields function as below:
_buildTaxInputFields() {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
initialValue: inputValue,
textAlign: TextAlign.left,
onSaved: () {},
decoration: kTextFieldDecoration.copyWith(hintText: 'tax name e.g. VAT, service charge, etc'),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
initialValue: inputValue,
textAlign: TextAlign.left,
onSaved: () {},
decoration: kTextFieldDecoration.copyWith(hintText: 'tax percentage e.g. 20, 19.5'),
),
Row(
children: <Widget>[
Expanded(
flex: 1,
child: RadioListTile(
title: Text('I\'ll bear it '),
value: TaxBearer.merchant,
groupValue: _taxBearer,
onChanged: (TaxBearer value) {
setState(() {
_taxBearer = value;
});
},
),
),
Expanded(
flex: 1,
child: RadioListTile(
title: Text('Push to customer'),
value: TaxBearer.customer,
groupValue: _taxBearer,
onChanged: (TaxBearer value) {
setState(() {
_taxBearer = value;
});
}),
),
],
),
],
);
}
Your visibility widget will never be rendered because you're generating it in the onPressed method of a button.
You could use a column to generate it below the button like this:
bool _addNewTax = false;
Column(
children: [
FlatButton.icon(
color: kBgCircleColour,
padding: EdgeInsets.all(15.0),
icon: Icon(
FontAwesomeIcons.plusSquare,
color: kThemeStyleButtonFillColour,
),
onPressed: () {
setState(() {
_addNewTax = true;
});
},
label: Text(
'Add new tax',
style: kRegularTextStyle,
),
),
Visibility(
visible: _addNewTax,
child: _buildTaxInputFields(),
),
],
);

Column take all the screen

I'm making a flutter app in which I use an AlertDialog widget
Here is a screen in which you can understand where the problem is :
Here is a piece of my code used for that
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: Text('Ajouter un ingrédient'),
content: new Column(
children: <Widget>[
Container(
child: DropDownButtonIngredients(),
),
Container(
child: new TextField(
autofocus: false,
decoration: new InputDecoration(
labelText: 'Nom', hintText: 'Frite, Steak, Salade ...'),
onChanged: (value) {
newIngr = value;
},
)),
],
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Note : I already tried to remove the DropDownButtonIngredients container, nothing new, same for the other container
Set mainAxisSize to MainAxisSize.min:
Column(
mainAxisSize: MainAxisSize.min,
...
);

TextFormField losing value when changing focus

I am trying to move to other TextFormField but whenever I lose focus from first TextFormField text became empty, I search about this issue but I don't find any solution till now.
var _formKey = GlobalKey<FormState>();
Note note;
TextEditingController titleController=TextEditingController();
TextEditingController descriptionController=TextEditingController();
#override
Widget build(BuildContext context) {
TextStyle textStyle=Theme.of(context).textTheme.title;
titleController.text=note.title;
descriptionController.text=note.description;
// TODO: implement build
return WillPopScope(
onWillPop: (){
moveToLastScreen();
},
child:Scaffold(
appBar: AppBar(
title: Text("appBarTitle"),
leading: IconButton(icon:Icon(Icons.arrow_back),onPressed: (){
moveToLastScreen();
},),
),
body: Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.only(top: 15.0,left: 15.0,right: 10.0),
child: ListView(
children: <Widget>[
//1st element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0,),
child: TextFormField(
validator: (String value){
if(value.isEmpty)
{
return "Please enter Title";
}
},
controller: titleController,
style: textStyle,
onSaved: (value){
debugPrint("Something changed in title Text field");
updateTitle();
},
/*onChanged: (value){
debugPrint("Something changed in title Text field");
updateTitle();
},*/
decoration: InputDecoration(
labelText: "Title",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)
)
),
),
),
//2nd element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0,),
child: TextFormField(
validator: (String value){ //2nd step for form with validation
if(value.isEmpty)
{
return "Please enter principle amount";
}
},
onSaved: (value){
debugPrint("Something changed in Description Text field");
updateDescription();
},
controller: descriptionController,
style: textStyle,
/*onChanged: (value){
debugPrint("Something changed in Description Text field");
updateDescription();
},*/
decoration: InputDecoration(
labelText: "Description",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)
)
),
),
),
//3th element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
color: Theme.of(context).primaryColorDark,
textColor: Theme.of(context).primaryColorLight,
child: Text("Save",textScaleFactor: 1.5,),
onPressed: (){
setState(() {
if(_formKey.currentState.validate()) {
debugPrint("Save Pressed");
_save();
}
});
}
),
),
Container(width: 5.0,),
Expanded(
child: RaisedButton(
color: Theme.of(context).primaryColorDark,
textColor: Theme.of(context).primaryColorLight,
child: Text("Delete",textScaleFactor: 1.5,),
onPressed: (){
setState(() {
debugPrint("Delete Pressed");
_delete();
});
}
),
),
],
),
),
],
),
)),
));
}
Please suggest me I am new in flutter.
Remove titleController.text=note.title; descriptionController.text=note.description; from your build method and place it in initState method.
You will lose the value in the textField because those lines get executed anytime there is a rebuild, thereby replacing the values gotten from the textFields and replacing it with note.title and note.description which are empty at that point.
In other words, remove those lines and add this to your code.
#override
void initState() {
super.initState();
titleController.text=note.title;
descriptionController.text=note.description;
}