TextFormField value not updating as intended in flutter - dart

I have a strange problem in my application I have a signup page with several textformfields inside a ListView and the ListView is a child to the Form.
when i reach the last formfield inside the ListView i need to scroll up the screen to actually see what i am typing inside the field. When i do scroll up the textformfields which go out of focus are losing the entered text and are initialised as null. I am not sure what i am missing or do i have to use some other way to make sure i retain the TextFormField values. I have tried to use the controller in every TextFormField then it is retaining the value even if I scroll up. But, the properties of the object e.g, hostelData.hostelName are only updated first time and the changes are not reflected in the object property from the second time. I am not so sure what i am missing? Please can someone help me in solving this.
Please excuse my mistakes in posting as i am new to programming and any help would be greatly appreciated.
I have posted the code below so that you can reproduce the same problem.
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:myhostel/theme.dart' as Theme;
import 'package:myhostel/globals.dart' as gl;
class SignUp extends StatefulWidget {
const SignUp({ Key key }) : super(key: key);
#override
_SignUpState createState() => new _SignUpState();
}
class HostelData{
String hostelName = '';
String ownersName = '';
String mobileNumber = '';
String emailId = '';
String password = '';
String city = '';
String hostelType= 'mens';
String confirmPassword ='';
}
class _SignUpState extends State<SignUp> {
HostelData hostelData = new HostelData();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value),
duration: const Duration(milliseconds: 3000),
));
}
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
final GlobalKey<FormFieldState<String>> _passwordFieldKey = new
GlobalKey<FormFieldState<String>>();
bool _autovalidate = false;
bool _formWasEdited = false;
void _handleSubmitted() {
final FormState form = _formKey.currentState;
if (!form.validate()) {
_autovalidate = true; // Start validating on every change.
showInSnackBar('Please fix the errors in red before submitting.');
} else {
form.save();
showInSnackBar('${hostelData.ownersName}\'s hostel name is
${hostelData.hostelName}');
_createuserwithemailandpassword();
}
}
String _validateName(String value) {
_formWasEdited = true;
if (value.isEmpty)
return 'Name is required.';
final RegExp nameExp = new RegExp(r'^[A-Za-z ]+$');
if (!nameExp.hasMatch(value))
return 'Please enter only alphabetical characters and spaces.';
return null;
}
String _validatePassword(String value) {
_formWasEdited = true;
final FormFieldState<String> passwordField =
_passwordFieldKey.currentState;
if (passwordField.value == null || passwordField.value.isEmpty)
return 'Please choose a password.';
if (passwordField.value != value)
return 'Passwords don\'t match';
return null;
}
#override
Widget build(BuildContext context){
return new MaterialApp(
theme: Theme.MyHostelThemeData,
home: new Scaffold(
key: _scaffoldKey,
body: new Container(
child: new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/bg.png'),
fit: BoxFit.fill,
),
),
child: new Form(
key: _formKey,
autovalidate: _autovalidate,
child: new ListView(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(top:32.0),
child: new Center(
child: new Text('SIGN UP',
style: new TextStyle(
color: const Color(0xFFF5FEFD),fontSize:24.0,fontWeight:
FontWeight.bold),
),
),
),
new Row(
children:[
new Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 24.0,right: 12.0,),
child:new TextFormField(decoration: new InputDecoration(
/*hintStyle: new TextStyle(
fontSize: 20.0,color: const Color(0xFFF5FEFD),),*/
labelText: 'Hostel Name',
),
/*style: new TextStyle(
fontSize: 20.0,
color: Colors.white,
),*/
onSaved:(String value){ hostelData.hostelName = value; },
validator: _validateName,
),
),
),
],
),
new Row(
children:[
/*new Container(
margin: const EdgeInsets.all(8.0),
width: 24.0,
child: new Image.asset(
'assets/person_avatar.png',
fit: BoxFit.contain,
//alignment: FractionalOffset.center,
),
),*/
new Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 24.0,right: 12.0,),
child:new TextFormField(
//controller: _ownersNameController,
decoration: new InputDecoration(//hintText: 'Mobile
Number',
/* hintStyle: new TextStyle(fontSize: 20.0,color: const
Color(0xFFF5FEFD),),*/
labelText: 'Owners Name',
),
/*style: new TextStyle(
fontSize: 20.0,
color: Colors.white,
),*/
onSaved: (String value) { hostelData.ownersName = value;
},
validator: _validateName,
),
),
),
],
),
new Row(
children:[
new Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 24.0,right: 12.0,),
child:new TextFormField(
//controller: _mobileNumberController,
keyboardType: TextInputType.phone,
decoration: new InputDecoration(//hintText: 'Mobile
Number',
/* hintStyle: new TextStyle(fontSize: 20.0,color:
const Color(0xFFF5FEFD),),*/
labelText: 'Mobile Number',
//prefixText: '+91',
),
/*style: new TextStyle(
fontSize: 20.0,
color: Colors.white,
),*/
onSaved: (String value) { hostelData.mobileNumber = value; },
//validator: _validatePhoneNumber,
),
),
),
],
),
//implements EmailID Row
new Row(
children:[
new Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 24.0,right: 12.0,),
child:new TextFormField(
//controller: _emailIdController,
decoration: new InputDecoration(
//hintText: 'Mobile Number',
/*hintStyle: new TextStyle(fontSize: 20.0,color: const
Color(0xFFF5FEFD),),*/
labelText: 'EMail Id',
helperText: 'Required',
),
/*style: new TextStyle(
fontSize: 20.0,
color: Colors.white,
),*/
onSaved: (String value){hostelData.emailId = value;},
),
),
),
],
),
//implements the password row
new Container(
padding: const EdgeInsets.only(left: 8.0,),
child: new Row(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(top: 16.0),
//padding: const EdgeInsets.all(8.0),
child: new Icon(Icons.lock_outline,
color: const Color(0xFFF5FEFD)
),
),
new Expanded(
child: new Container(
margin: const EdgeInsets.only(
left: 28.0, right: 12.0,),
child: new TextFormField(
key: _passwordFieldKey,
//controller: _passwordController,
decoration: const InputDecoration(
hintText: 'min 8 characters',
labelText: 'Password',
helperText: 'Required',
),
autocorrect: false,
//obscureText: true,
//validator: 'Required',
/*style: DefaultTextStyle.of(context).style.merge(new
TextStyle(
fontSize: 16.0,
color: CustomColors.fontColor,
),
),*/
onSaved: (String value){hostelData.password = value;},
),
),
),
],
),
),
new Container(
padding: const EdgeInsets.only(left: 8.0,),
child: new Row(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(top: 16.0),
//padding: const EdgeInsets.all(8.0),
child: new Icon(Icons.lock_outline,
color: const Color(0xFFF5FEFD)
),
),
new Expanded(
child: new Container(
margin: const EdgeInsets.only(
left: 28.0, right: 12.0,),
child: new TextFormField(
//controller: _confirmpasswordcontroller,
decoration: const InputDecoration(
labelText: 'Confirm Password',
helperText: 'Required'
),
autocorrect: false,
// obscureText: true,
//validator: 'Required',
/*style: DefaultTextStyle.of(context).style.merge(new
TextStyle(
fontSize: 16.0,
color: CustomColors.fontColor,
),
),*/
//onSaved: (String value){hostelData.confirmPassword =
value;},
validator: _validatePassword,
),
),
),
],
),
),
new Row(
children:[
new Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 24.0,right: 12.0,),
child:new TextFormField(
controller: _cityController,
decoration: new InputDecoration(labelText: 'City*'),
onSaved: (String value){hostelData.city = value;},
validator: _validateName,
),
),
),
],
),
new Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.only(left:24.0,right: 24.0),
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.white,
width: 2.0,
),
borderRadius: new BorderRadius.all(const
Radius.circular(32.0),)
),
child: new FlatButton(
onPressed: ((){
print('SignUp Button Clicked');
_handleSubmitted();
}),
child: new Text (
'SIGN UP',
style: new TextStyle(fontSize: 24.0,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
new Row(
children:[
new Container(
margin: const EdgeInsets.only(left: 24.0,bottom: 12.0),
child:new Text(
'Already have an account?',
style: new TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
new Container(
padding: const EdgeInsets.only(right: 8.0,top:
4.0,bottom:16.0),
margin: const EdgeInsets.only(right: 12.0,left: 4.0),
child:
new MaterialButton(
onPressed: ((){
//Sign In Button pressed declaration here
print('sign in button clicked');
}),
child: new Text('SignIn',
style: new TextStyle(
fontSize: 16.0,
color: Colors.teal[200],
),
),
minWidth: 16.0,
),
),
],
),
new Container(
padding: const EdgeInsets.only(left: 16.0),
child: new Text('* indicates required field',
style: new TextStyle(
fontSize: 14.0,
color: Colors.white,
),),
),
]
),
),
),
),
),
);
} // widget ends here
globals.dart
library my_hostel.globals;
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
final FirebaseAuth auth = FirebaseAuth.instance;
final DatabaseReference messagesRef =FirebaseDatabase.instance.reference();

Here is an example of working code:
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String s1 = "";
String s2 = "";
String s3 = "";
String s4 = "";
String s5 = "";
final TextEditingController c1 = new TextEditingController();
final TextEditingController c2 = new TextEditingController();
final TextEditingController c3 = new TextEditingController();
final TextEditingController c4 = new TextEditingController();
final TextEditingController c5 = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Example"),),
body: new ListView(
children: <Widget>[
new Padding(padding: new EdgeInsets.all(70.0),),
new TextField(
controller: c1,
onChanged: (String text) {
s1 = text;
},
),
new Padding(padding: new EdgeInsets.all(70.0),),
new TextField(
controller: c2,
onChanged: (String text) {
s2 = text;
},
),
new Padding(padding: new EdgeInsets.all(70.0),),
new TextField(
controller: c3,
onChanged: (String text) {
s3 = text;
},
),
new Padding(padding: new EdgeInsets.all(70.0),),
new TextField(
controller: c4,
onChanged: (String text) {
s4 = text;
},
),
new Padding(padding: new EdgeInsets.all(70.0),),
new TextField(
controller: c5,
onChanged: (String text) {
s5 = text;
},
),
],
)
);
}
}
You need to add a TextEditingController with your TextField. Listview removes invisible widgets because rendering a ton of widgets that are not being displayed would make it perform worse!

Related

unable to display snackbar in flutter

I am very new to flutter and stuck on the point of displaying a SnackBar when login fails .Kindly check the code below and let me know how to fix this problem. I don't know where exactly do I need to have builder. You can suggest to me the best solution to display SnackBar in a simple and quick way. Many thanks in advance to all those who will help.
class LoginPage extends StatefulWidget {
static String tag = 'login-page';
#override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool passwordVisible = true;
var _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
final logo = Hero(
tag: 'hero',
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 48.0,
child: Image.asset('assets/splash.png'),
),
);
/* final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: 'mufeez#gmail.com',
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
*/
final password = TextFormField(
autofocus: false,
obscureText: passwordVisible,//This will obscure text dynamically
decoration: InputDecoration(
hintText: 'Enter Secret Key',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
suffixIcon: IconButton(
icon: Icon(
// Based on passwordVisible state choose the icon
passwordVisible
? Icons.visibility_off
: Icons.visibility,
color: Theme.of(context).primaryColorDark,
),
onPressed: () {
// Update the state i.e. toogle the state of passwordVisible variable
setState(() {
passwordVisible
? passwordVisible = false
: passwordVisible = true;
});
},
),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: () async {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
Scaffold.of(context).showSnackBar(snackBar);
},
padding: EdgeInsets.all(12),
color: Colors.lightBlueAccent,
child: Text('Log In', style: TextStyle(color: Colors.white)),
),
);
/* final forgotLabel = FlatButton(
child: Text(
'Forgot password?',
style: TextStyle(color: Colors.black54),
),
onPressed: () {},
);
*/
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
logo,
SizedBox(height: 48.0),
SizedBox(height: 8.0),
password,
SizedBox(height: 24.0),
loginButton,
],
),
),
);
}
you have to use scaffold key to do so.
what you have to add in scaffold widget.
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
and at the time of display snackbar you have to use scaffold key.
replace your onPressed with below code.
onPressed: () async {
final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
_scaffoldKey.currentState.showSnackBar(snackBar);
},
You can also wrap your Scaffold body in a Builder() widget.
return Scaffold(
body: body: Builder(
builder: (BuildContext ctxt) {
return (your content here);}));
and when want to display the Snackbar juste use Scaffold.of(ctxt) onPressed
onPressed: () {
Scaffold.of(ctxt).showSnackBar(
SnackBar(content:Text('My snack')));
},

Flutter : A build function returned null and NoSuchMethodError: The method '[]' was called on null

I build a form for user profile data, but why always display messages in my debug console like this :
I/flutter (31833): Another exception was thrown: A build function
returned null. I/flutter (31833): Another exception was thrown:
NoSuchMethodError: The method '[]' was called on null. I/flutter
(31833): Another exception was thrown: NoSuchMethodError: The method
'[]' was called on null.
and this my full code :
import 'package:flutter/material.dart';
class EditProfile extends StatefulWidget {
final String value;
EditProfile({Key key, this.value}) : super(key: key);
#override
_EditProfileState createState() => _EditProfileState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
String selectSex;
class _EditProfileState extends State<EditProfile> {
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text('Edit Profile'),
),
body: new Padding(
padding: const EdgeInsets.all(10.0),
child: new SingleChildScrollView(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: new TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'First Name'),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: new TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: 'Birth Date'),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: new Container(
decoration: new BoxDecoration(
border: new Border.all(color: Colors.black),
borderRadius: new BorderRadius.all(Radius.circular(4.0)),
),
height: 55.0,
width: double.infinity,
child: new DropdownButtonHideUnderline(
child: new DropdownButton<String>(
hint: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Text('Sex'),
),
value: selectSex,
items: <String>['Man', 'Woman']
.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Padding(
padding: const EdgeInsets.all(10.0),
child: new Text(value),
),
);
}).toList(),
onChanged: (value) {
print(value);
setState(() {
selectSex = value;
});
},
),
),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: new TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: ' Handphone'),
),
),
new Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: new TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'Status'),
),
),
new SizedBox(
width: double.infinity,
child: new RaisedButton(
child: new Text(
'Save',
style: TextStyle(color: Colors.white),
),
color: Colors.orange,
onPressed: () {
}),
),
],
),
),
),
);
}
}
You should check your items value:
items: <String>['Man', 'Woman']
.map((value) { // remove the `String` attribute
return new DropdownMenuItem<String>(
value: value,
child: new Padding(
padding: const EdgeInsets.all(10.0),
child: new Text(value),
),
);
}).toList(),

Flutter code, accept value from user display required field

**Hello, I am developing an app in which the user should enter the integer values.according to that values we should display those number of text fields..
for Example:
1) enter total number of subject=10;
2) click on the button;
3) After button is clicked should display 10 text fields;
4) I have no idea what to do so if you know then help me plz.**
import 'package:flutter/material.dart';
class imcaaddsubject extends StatefulWidget {
#override
_imcaaddsubjectState createState() => _imcaaddsubjectState();
}
class _imcaaddsubjectState extends State<imcaaddsubject> {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(5),
child: Card(
child: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
),
new TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(style: BorderStyle.solid)),
labelText: "NUMBER OF SUBJECTS",
hintText: "Enter number of subjects",
),keyboardType: TextInputType.number,
),
Padding(
padding: EdgeInsets.only(top: 15),
),
new RaisedButton(
child: Text(
"OK",
style:
TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
color: Colors.cyan,
onPressed: () {},
)
],
),
),
);
}
}
You can try like this :
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
int numberOfSubjects = 0;
Widget subjectsBuilder(int numberOfSubjects) {
if (numberOfSubjects > 0) {
return ListView.builder(
itemBuilder: (BuildContext context, numberOfSubjects) {
return TextField(
decoration: InputDecoration(hintText: "enter a text"),
);
},
itemCount: numberOfSubjects,
);
} else {
return SizedBox();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Card(
child: ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
),
new TextField(
onSubmitted: (String value) {
setState(() {
numberOfSubjects = int.parse(value);
});
},
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(style: BorderStyle.solid)),
labelText: "NUMBER OF SUBJECTS",
hintText: "Enter number of subjects",
),
keyboardType: TextInputType.number,
),
Padding(
padding: EdgeInsets.only(top: 15),
),
],
),
),
),
),
Expanded(
child: subjectsBuilder(numberOfSubjects),
)
]),
);
}
}
this code will display a number of text fields according to user input below the first text field , of course you can render it in a new page .. also you don't have to use a button , it's enough to user submit text .

TextFormField is not working properly, its blinking continuously

TextFormField is not working properly, its blinking continuously and it doesn't allow me to write anything, as I tap on the TextFormField my keyboard appears for a second and disappear instantly. I am confused what wrong I have done with my code, I've matched my code with previous working code, but still getting this behaviour .
Here is my code.
class ComingSoonState extends State<ComingSoon> {
String language;
TextEditingController _textEdititingController ;
#override
void initState() {
_textEdititingController = new TextEditingController(); //Initialised TextEditingController
super.initState();
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final Size size = MediaQuery.of(context).size;
final formData = new Form(
key: widget._formKey,
child: new Container(
padding: const EdgeInsets.only(
left: 35.0,
right: 35.0),
child: new Column(
children: <Widget>[
new Theme(
data: theme.copyWith(primaryColor: Colors.black54),
child: new TextFormField(
controller: _textEdititingController, //ADDED CONTROLLER HERE
style: const TextStyle(color: Colors.black54),
decoration: new InputDecoration(
labelText: 'Amount',
labelStyle: const TextStyle(color: Colors.black54)
),
// validator: this._validateEmail,
validator: (val) {
return val.isEmpty
? "Please enter amount"
: null;
},
onSaved: (String value) {
// this._data.email = value;
this.language = value;
}
),
),
],
),
),
);
return Scaffold(
appBar: new AppBar(
leading: null,
title: const Text('Send Money', style: const TextStyle(
color: Colors.white
),
),
),
body: new Container(
color: Colors.grey[300],
child: new ListView(
children: <Widget>[
new Container(
child: new Column(
children: <Widget>[
new Container(
height: 60.0 ,
padding: const EdgeInsets.all(5.0),
child: new Card(
child: new Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text("Available balance in wallet", style:
new TextStyle(color: Colors.black54,
fontSize: 16.0
),),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text("123 KSH", style:
new TextStyle(color: Colors.blueAccent,
fontSize: 16.0
),),
),
],
),
),
) ,
new Container(
//height: 300.0,
padding: const EdgeInsets.all(5.0),
child: new Card(
child: new Container(
child: new Center(
child: new Column(
children: <Widget>[
formData
],
),
),
),
),
)
],
)
),
],
),
),
);
}
}
I added a floating action button that presents a dialog that will show what you entered into the TextField (using the controller). I'm not sure what form key you were passing in before but making the GlobalKey instance a member variable eliminates the keyboard present/dismiss issue.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String language;
TextEditingController _textEditingController;
final _formKey = GlobalKey<FormState>();
#override
void initState() {
_textEditingController =
TextEditingController(); //Initialised TextEditingController
super.initState();
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final Size size = MediaQuery.of(context).size;
final formData = Form(
key: _formKey,
child: Container(
padding: const EdgeInsets.only(left: 35.0, right: 35.0),
child: Column(
children: <Widget>[
Theme(
data: theme.copyWith(primaryColor: Colors.black54),
child: TextFormField(
controller: _textEditingController,
//ADDED CONTROLLER HERE
style: const TextStyle(color: Colors.black54),
decoration: InputDecoration(
labelText: 'Amount',
labelStyle: const TextStyle(color: Colors.black54)),
// validator: this._validateEmail,
validator: (val) {
return val.isEmpty ? "Please enter amount" : null;
},
onSaved: (String value) {
// this._data.email = value;
language = value;
}),
),
],
),
),
);
return Scaffold(
appBar: AppBar(
leading: null,
title: const Text(
'Send Money',
style: const TextStyle(color: Colors.white),
),
),
body: Container(
color: Colors.grey[300],
child: ListView(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Container(
height: 60.0,
padding: const EdgeInsets.all(5.0),
child: Card(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"Available balance in wallet",
style: TextStyle(
color: Colors.black54, fontSize: 16.0),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"123 KSH",
style: TextStyle(
color: Colors.blueAccent, fontSize: 16.0),
),
),
],
),
),
),
Container(
//height: 300.0,
padding: const EdgeInsets.all(5.0),
child: Card(
child: Container(
child: Center(
child: Column(
children: <Widget>[formData],
),
),
),
),
)
],
)),
],
),
),
floatingActionButton: FloatingActionButton(
// When the user presses the button, show an alert dialog with the
// text the user has typed into our text field.
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the user has typed in using our
// TextEditingController
content: Text(_textEditingController.text),
);
},
);
},
tooltip: 'Show me the value!',
child: Icon(Icons.text_fields),
),
);
}
}

Flutter combo box

I am trying to create a dropdown / combobox widget and having a hard time to figure. Below is the code that I have tried. Basically creating a list that I gathered from here and there but not able to put it in my own code accordingly.
import 'package:flutter/material.dart';
class Signup extends StatefulWidget{
Signup({Key key}) : super (key:key);
final String title;
#override
SignupPage createState() => new SignupPage();
}
class SignupPage extends State<Signup> {
#override
Widget build(BuildContext context) {
List _countrycodes = ["+65","+91"];
List<DropdownMenuItem<String>> _dropDownMenuItems;
String _selectedCountryCode;
List<String> _colors = <String>['', 'red', 'green', 'blue', 'orange'];
String _color = '';
List<DropdownMenuItem<String>> getDropDownMenuItems() {
List<DropdownMenuItem<String>> items = new List();
for (String code in _countrycodes) {
items.add(new DropdownMenuItem(
value: code,
child: new Text(code)
));
}
return items;
}
/**return new Material(
color: Colors.blueAccent,
child: new Scaffold(
body: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(image: new AssetImage("assets/images/download.jpg"), fit: BoxFit.cover,),
),
),
new Center(
child: new Text("Hello LandingPage"),
)
],
)
));**/
final name = TextFormField(
keyboardType: TextInputType.text,
autofocus: false,
initialValue: 'Techie Quickie',
decoration: InputDecoration(
hintText: 'Name',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: 'tq#gmail.com',
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final password = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final passwordConfirmation = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: (){
print("Signup button clicked");
},
color: Colors.lightBlueAccent,
child:
Text('Sign Up',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
)
);
final countryCode = DropdownButton(
value: _selectedCountryCode,
items: _dropDownMenuItems,
onChanged: null
);
final inputDecoratoring =InputDecorator(
decoration: const InputDecoration(
icon: const Icon(Icons.color_lens),
labelText: 'Color',
),
isEmpty: _color == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton<String>(
value: _color,
isDense: true,
onChanged: (String newValue) {
setState(() {
_color = newValue;
});
},
items: _colors.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
),
),
);
return Scaffold(
backgroundColor: Colors.white,
body: Center (
child: ListView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
shrinkWrap: true,
children: <Widget>[
name,
SizedBox(height: 18.0),
email,
SizedBox(height: 18.0),
password,
SizedBox(height: 18.0),
passwordConfirmation,
SizedBox(height: 18.0),
// countryCode,
// SizedBox(height: 18.0),
loginButton,
SizedBox(height: 38.0),
],
)
)
);
}
}
This is my main.dart class
import 'package:flutter/material.dart';
import 'package:elegal_dart/screens/landing_page.dart';
import 'package:elegal_dart/screens/home.dart';
import 'package:elegal_dart/screens/devices.dart';
import 'package:elegal_dart/screens/signup.dart';
import 'package:elegal_dart/screens/signin.dart';
/*
void main()
{
Devices( new MaterialApp(
home: new Devices(),
));
}*/
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget
{
#override
Widget build(BuildContext context)
{
return new MaterialApp(
title: 'Navigation',
routes: <String, WidgetBuilder>
{
'/Home' : (BuildContext context) => new Home(),
'/LandingPage' : (BuildContext context) => new LandingPage(),
'/Devices' : (BuildContext context) => new Devices(),
'/Signup' : (BuildContext context) => new Signup(),
'/Signin' : (BuildContext context) => new Signin(),
},
//home: new Signin(onSubmit: null),
home: new Signup(),
);
}
}
UPDATED CODE:
import 'package:flutter/material.dart';
class Signup extends StatefulWidget{
Signup({Key key}) : super (key:key);
final String title;
#override
SignupPage createState() => new SignupPage();
}
class SignupPage extends State<Signup> {
#override
Widget build(BuildContext context) {
List _countrycodes = ["+65","+91"];
List<DropdownMenuItem<String>> _dropDownMenuItems;
String _selectedCountryCode;
List<String> _ccodes = <String>['', '+65', '+91', '+60', 'orange'];
String _ccode = '';
List<DropdownMenuItem<String>> getDropDownMenuItems() {
List<DropdownMenuItem<String>> items = new List();
for (String code in _countrycodes) {
items.add(new DropdownMenuItem(
value: code,
child: new Text(code)
));
}
return items;
}
final name = TextFormField(
keyboardType: TextInputType.text,
autofocus: false,
initialValue: 'Techie Quickie',
decoration: InputDecoration(
hintText: 'Name',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: 'tq#gmail.com',
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final password = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final passwordConfirmation = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: (){
print("Signup button clicked");
},
color: Colors.lightBlueAccent,
child:
Text('Sign Up',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
)
);
final countryCode = DropdownButtonHideUnderline (
child: DropdownButton<String>(
value: _ccode,
isDense: true,
items: _ccodes.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_ccode = newValue;
});
}
)
);
return Scaffold(
backgroundColor: Colors.white,
body: Center (
child: ListView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
shrinkWrap: true,
children: <Widget>[
name,
SizedBox(height: 18.0),
email,
SizedBox(height: 18.0),
password,
SizedBox(height: 18.0),
passwordConfirmation,
SizedBox(height: 18.0),
countryCode,
SizedBox(height: 18.0),
loginButton,
SizedBox(height: 38.0),
],
)
)
);
}
}
The error that I am getting in the AVD
The assertion tells you that items must not be null. It's referring to this one: items: _dropDownMenuItems,. You don't ever assign _dropDownMenuItems.
This is a good use for a Dart-y pattern. Replace it with:
final countryCode = DropdownButton(
value: _selectedCountryCode,
items: _countrycodes
.map((code) =>
new DropdownMenuItem(value: code, child: new Text(code)))
.toList(),
onChanged: null,
);
and you no longer need the field or the getDropDownMenuItems function. If you aren't familiar with this syntax, read it as "map each code in countryCodes to a DropdownMenuItem and form them back into a List"
Also, the scope of your variables is wrong. Move them out of the build function and into the State, like this:
class SignupPage extends State<Signup> {
List<String> _countrycodes = ["+65", "+91"];
List<String> _colors = ['', 'red', 'green', 'blue', 'orange'];
String _selectedCountryCode;
String _color = '';
My answer will solve also the problem of using more than one DropdownButton in the same page without the error of more than 1 item in the DropdownMenuItem .
First define the lists you will use this way:
static const List<String> _razas = const
["Schnauzer", "Ovejero Alemán", "Husky", "Brasov",
"Constanta","Mestizo"];
////////barrios
static const List<String> _barrios = const
"Belgrano", "Caballito", "Colegiales", "Lugano", "Palermo","Pilar",
"Montserrat", "Vicente López" ];
static const List<String> _tamanio = const
["Chico", "Mediano", "Grande" ];
String tamanioValue = _tamanio[0];
String barriosValue = _barrios[0];
String razasValue = _razas[0];
Then use this Containers in your Scaffold
Container(
margin: EdgeInsets.only(top:20.0, bottom: 20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
children:<Widget> [
Text("RAZA "),
new DropdownButton(value:razasValue,
onChanged: (string) => setState(() => razasValue =
string),
items: _razas.map((string) {
return new DropdownMenuItem(
child: new Text(string),
value: string,
);
}).toList(),
),
]
)
),
Container(
margin: EdgeInsets.only(top:20.0, bottom: 20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
children:<Widget> [
Text("BARRIO "),
new DropdownButton(value:barriosValue,
onChanged: (string) => setState(() =>
barriosValue = string),
items: _barrios.map((string) {
return new DropdownMenuItem(
child: new Text(string),
value: string,
);
}).toList(),
),
]
)
),
Then just replace the values for you database or any file you store the data
raza: razasValue,
barrio: barriosValue,

Resources