I am working on a Flutter app.
I have this dart code:
List<Widget> buildInputs() {
return[
new Container(
padding: new EdgeInsets.only(
top: 20.0,
right: 40.0,
left: 40.0,
),
child: new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(labelText: 'E-Mail', contentPadding: new EdgeInsets.only(bottom: 1.0)),
validator: (value) => value.isEmpty ? 'Email can\'nt be empty' : null,
onSaved: (value) => _email = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: 'Password', contentPadding: new EdgeInsets.only(bottom: 1.0)),
obscureText: true,
validator: (value) => value.isEmpty ? 'Password can\'nt be empty' : null,
onSaved: (value) => _password = value,
),
],
),
),
];
}
As you can see I use this: contentPadding: new EdgeInsets.only(bottom: 1.0)
I use this that the title of the TextFormField is closer too the TextFormFieldLine.
Now, how to add a top space between the two TextFormFields.
There Are Few Ways to get it Done :
1st Padding Widget: Wrap With Form Field with Padding Widget
Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 25.0),
child: new TextFormField(
decoration: new InputDecoration(
labelText: 'E-Mail',
contentPadding: new EdgeInsets.only(bottom: 1.0)),
validator: (value) =>
value.isEmpty ? 'Email can\'nt be empty' : null,
// onSaved: (value) => _email = value,
),
),
Padding(
padding: EdgeInsets.only(top: 25.0),
child: new TextFormField(
decoration: new InputDecoration(
labelText: 'Password',
contentPadding: new EdgeInsets.only(bottom: 1.0)),
obscureText: true,
validator: (value) =>
value.isEmpty ? 'Password can\'nt be empty' : null,
// onSaved: (value) => _password = value,
),
),
],
),
2nd SizedBox Widget: I prefer this method to add space between Form Fields as its clean & less Code.
Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(
labelText: 'E-Mail',
contentPadding: new EdgeInsets.only(bottom: 1.0)),
validator: (value) =>
value.isEmpty ? 'Email can\'nt be empty' : null,
// onSaved: (value) => _email = value,
),
SizedBox(height: 25.0,),
new TextFormField(
decoration: new InputDecoration(
labelText: 'Password',
contentPadding: new EdgeInsets.only(bottom: 1.0)),
obscureText: true,
validator: (value) =>
value.isEmpty ? 'Password can\'nt be empty' : null,
// onSaved: (value) => _password = value,
),
],
),
You can just add a SizedBox (a very basic widget without decoration) between the text fields:
SizedBox(height: 8.0)
You could also use Wrap(runSpacing:8, children:[])
Related
I have a TextFormField with validation on Empty.
In order to control height, TextFormField was nested inside Container widget.
Which cause unexpected side effect of displaying error message overlap as attached pictures.
to test sample code, press "Submit" to see error.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: SimpleForm(),
);
}
}
class SimpleForm extends StatelessWidget {
#override
Widget build(BuildContext context) {
final formKey = GlobalKey<FormState>();
return SafeArea(
child: Scaffold(
// primary: true,
body: Form(
key: formKey,
child: Column(
children: [
SizedBox(
height: 0,
),
// Container(height: 0,),
Container(
height: 38,
margin: EdgeInsets.all(6),
child: TextFormField(
maxLines: 1,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Name',
// errorStyle: TextStyle(fontSize: 0, height: 0),
),
validator: (value) => (value.isEmpty) ? '**' : null,
),
),
FlatButton(
child: Text('Submit'),
onPressed: () {
formKey.currentState.validate();
},
)
],
),
)),
);
}
}
Solution 1. You can set helperText for the TextField's decoration and increase the Container's height:
Container(
height: 60,
child: TextFormField(
maxLines: 1,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Name',
helperText: ' ', // this is new
),
validator: (value) => (value.isEmpty) ? '**' : null,
),
),
Solution 2. You can set the line height of the error message to 0 (it will be displayed above the text field):
Container(
height: 38,
child: TextFormField(
maxLines: 1,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Name',
errorStyle: TextStyle(height: 0), // this is new
),
validator: (value) => (value.isEmpty) ? '**' : null,
),
),
You can use this
TextFormField(
decoration: new InputDecoration(
enabledBorder: OutlineInputBorder( //change border of enable textfield
borderRadius: BorderRadius.all(Radius.circular(40.0)),
borderSide: BorderSide(color: colorValue),),
focusedBorder: OutlineInputBorder( //focus boarder
borderRadius: BorderRadius.all(Radius.circular(40.0)),
borderSide: BorderSide(color: colorValue),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1,color: Colors.red),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1,color: Colors.orange),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1,color: Colors.green),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1,)
),
errorBorder: OutlineInputBorder(. //error boarder
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1,color: Colors.black)
),
isDense: true,
counterText: "",
contentPadding: EdgeInsets.fromLTRB(10, 20, 10, 0), //padding according to your need
hintText: "create new",
hintStyle: TextStyle(color: colorValue, fontSize: 13)),
)),
Thanks for the answer Mobina,
Seem like issues is flutter limitation. For time being..
with border I decide to display error message on top. (Your solution :1)
without border I can display err msg as usual. (Your solution : 2)
// with border
Container(
height: 38,
margin: EdgeInsets.all(6),
child: TextFormField(
textAlignVertical: TextAlignVertical.bottom,
style: TextStyle(fontSize: 14),
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Name',
errorStyle: TextStyle(height: 0),
),
validator: (value) => (value.isEmpty) ? 'hide overlap' : null,
),
),
// without border
Container(
height: 38,
margin: EdgeInsets.all(6),
child: TextFormField(
textAlignVertical: TextAlignVertical.bottom,
style: TextStyle(fontSize: 14),
decoration: InputDecoration(
hintText: 'Name',
helperText: ' ', isDense: true,
counterText: "",
contentPadding: EdgeInsets.fromLTRB(10, 30, 10, 0),
),
validator: (value) => (value.isEmpty) ? 'hide overlap' : null,
),
),
i try to post http request to reset password, and i use Form widget with TextFormField to do it, but i get an error that the method validate().
i wrapped the TextFormField in a Form with a key, also i use the validator in the TextFormField.
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method 'validate' was called on null.
below is the widget code which i use to perform that.
import 'dart:io';
import 'package:Zabatnee/common_app/provider/user_details_provider.dart';
import 'package:Zabatnee/common_app/screens/signup_screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ResetPassword extends StatefulWidget {
static const routeName = '/resetCode';
#override
_ResetPasswordState createState() => _ResetPasswordState();
}
class _ResetPasswordState extends State<ResetPassword> {
final GlobalKey<FormState> _formKey = GlobalKey();
String code, _newPassword, _newConfirmPassword;
var _isLoading = false;
_showDialog(String title, String message, [bool navigate = false]) {
showDialog(
barrierDismissible: false,
context: context,
builder: (ctx) => WillPopScope(
onWillPop: () async => false,
child: new AlertDialog(
elevation: 15,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
title: Text(
title,
style: TextStyle(color: Colors.white),
),
content: Text(
message,
style: TextStyle(color: Colors.white),
),
backgroundColor: Theme.of(context).primaryColor,
actions: <Widget>[
FlatButton(
child: Text(
'OK',
style: TextStyle(color: Theme.of(context).accentColor),
),
onPressed: () {
Navigator.of(context).pop();
setState(
() {
_isLoading = false;
},
);
if (navigate) {
Navigator.of(context).pushNamed(SignupScreen.routeName);
}
},
)
],
),
),
);
}
void _removeFocus (){
FocusScopeNode currentFocus = FocusScope.of(context);
if(!currentFocus.hasPrimaryFocus){
currentFocus.unfocus();
}
}
Future<void> _resetPassword(String userCode, String userNewPassword) async{
_removeFocus();
final _isValid = _formKey.currentState.validate();
if(!_isValid){
return null;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try{
await Provider.of<UserDetailsProvider>(context, listen: false).resetPassword(userCode, userNewPassword);
_showDialog('Congartulations', 'Account has been created successfully.', true);
}on HttpException catch (error) {
_showDialog('Authentication Failed', error.message);
} on SocketException catch (_) {
_showDialog('An error occured',
'please check your internet connection and try again later');
} catch (error) {
_showDialog('Authentication Failed',
'Something went wrong, please try again later');
}
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
GlobalKey<FormState> _formKey = GlobalKey();
final _newPasswordFocusNode = FocusNode();
final _confirmPasswordFocusNode = FocusNode();
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: Text('Reset Password'),
),
backgroundColor: Colors.transparent,
body: Container(
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Please enter new password',
style: TextStyle(color:Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(
height: 30,
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: 'please enter reset code (check your email)',
focusColor: Theme.of(context).primaryColor,
fillColor: Colors.white,
labelText: 'Reset Code',
hintStyle: TextStyle(color:Colors.grey),
labelStyle: TextStyle(color:Colors.white),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1, color: Colors.grey),
),
border: OutlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).primaryColor)),
),
textInputAction: TextInputAction.next,
style: TextStyle(color:Colors.white),
onFieldSubmitted: (_){
FocusScope.of(context).requestFocus(_newPasswordFocusNode);
},
validator: (value){
if (value.isEmpty) {
return 'please enter a valid code';
}
return null;
},
onSaved: (value){
code = value;
},
),
SizedBox(
height: 15,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
textInputAction: TextInputAction.next,
style: TextStyle(color:Colors.white),
onFieldSubmitted: (_){
FocusScope.of(context).requestFocus(_confirmPasswordFocusNode);
},
validator: (value){
if(value.length<6){
return 'please enter password lager that 6 character';
}
return null;
},
onSaved: (value){
_newPassword = value;
},
decoration: InputDecoration(
hintText: 'please enter your password',
focusColor: Theme.of(context).primaryColor,
fillColor: Colors.white,
labelText: 'New password',
hintStyle: TextStyle(color:Colors.grey),
labelStyle: TextStyle(color:Colors.white),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1, color: Colors.grey),
),
border: OutlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).primaryColor)),
),
),
SizedBox(
height: 15,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
textInputAction: TextInputAction.done,
style: TextStyle(color:Colors.white),
onFieldSubmitted: (_){
FocusScope.of(context).requestFocus(_confirmPasswordFocusNode);
},
validator: (value){
if(value.length<6){
return 'please enter password lager that 6 character';
}
return null;
},
onSaved: (value){
_newConfirmPassword = value;
},
decoration: InputDecoration(
hintText: 'please retype your new password again',
focusColor: Theme.of(context).primaryColor,
fillColor: Colors.white,
labelText: 'Re-type new password',
hintStyle: TextStyle(color:Colors.grey),
labelStyle: TextStyle(color:Colors.white),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(width: 1, color: Colors.grey[100]),
),
border: OutlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).primaryColor)),
),
),
SizedBox(
height: 30,
),
if(_isLoading)
CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor,
),
if(!_isLoading)
RaisedButton(
child: Text('Reset', style: TextStyle(color:Colors.white, fontSize: 20),),
onPressed: (){
_resetPassword(code, _newPassword);
})
],
),
)
],
),
),
);
}
}
You declared 2 GlobalKeys under the same name _formKey. One is a field in the State class, the other at the top of the build method.
The key being passed to the form you're using is the one in build, which is overwritten on each build, because a new key is created and passed.
In your _resetPassword method, the classwide GlobalKey is used. This key is not attached to anything, and therefore, _formKey.currentState in that scope is null. This is what causes your exception.
To fix, simply remove GlobalKey<FormState> _formKey = GlobalKey(); from the beginning of your build method. The classwide GlobalKey will now be used instead.
i have textFeilds i put empty feild validation but i don't know how to put another validation(Multiple validation) like "Email is invalid" or whatever i want. This is just important code, all code is a lill lengthy
final TextEditingController _emailControl = new TextEditingController();
bool _validateEmail = false;
child: TextField(
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
borderSide: BorderSide(color: Colors.white,),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white,),
borderRadius: BorderRadius.circular(5.0),
),
hintText: "Email",
prefixIcon: Icon(
Icons.mail_outline,
color: Colors.black,
),
hintStyle: TextStyle(
fontSize: 15.0,
color: Colors.black,
),
labelText: 'Email',
errorText: _validateEmail ? 'Email Can\'t Be Empty' : null,
),
maxLines: 1,
controller: _emailControl,
),
My registration button press is below
onPressed: () {
setState(() {
_emailControl.text.isEmpty ? _validateEmail = true : _validateEmail = false;
if ( _validateEmail == false ){
_isLoading = true;
khan();
}
});
Use TextFormField.
TextFormField(
validator(val):{
if(val.isEmpty){
return "This field cannot be empty",
}
else if(next conditon){
return ....
}
}
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
borderSide: BorderSide(color: Colors.white,),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white,),
borderRadius: BorderRadius.circular(5.0),
),
hintText: "Email",
prefixIcon: Icon(
Icons.mail_outline,
color: Colors.black,
),
hintStyle: TextStyle(
fontSize: 15.0,
color: Colors.black,
),
labelText: 'Email',
errorText: _validateEmail ? 'Email Can\'t Be Empty' : null,
),
maxLines: 1,
controller: _emailControl,
),
And finally use form to validate the textfield.
import 'package:awwapp/Auth/registration.dart';
import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 20.0);
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
final emailField = TextField(
obscureText: false,
style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "Email",
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final passwordField = TextField(
obscureText: true,
style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "Password",
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final loginButon = Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Color(0xff01A0C7),
child: MaterialButton(
minWidth: MediaQuery.of(context).size.width,
padding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
onPressed: () {},
child: Text("Login",
textAlign: TextAlign.center,
style: style.copyWith(
color: Colors.white, fontWeight: FontWeight.bold)),
),
);
final registrationButton = Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Color(0xff01A0C7),
child: MaterialButton(
minWidth: MediaQuery.of(context).size.width,
padding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => RegistrationPage()),
);
},
child: Text("Register",
textAlign: TextAlign.center,
style: style.copyWith(
color: Colors.white, fontWeight: FontWeight.bold)),
),
);
return Scaffold(
body: Form(
key: _formKey,
child: Center(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 155.0,
child: Image.asset(
"assets/logo/logo.png",
fit: BoxFit.contain,
),
),
SizedBox(height: 45.0),
emailField,
SizedBox(height: 25.0),
passwordField,
SizedBox(
height: 35.0,
),
loginButon,
SizedBox(
height: 15.0,
),
registrationButton,
],
),
),
),
),
),
);
}
}
"TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
); "
here is the my whole code
i am creating login for my project and i want to validate these fields that is mention at above and i want to add code that i mentioned in double qoutes how i can add these code in my above mention code
i Want to validate these fields but i am facing errors plz help me how can i add
how i can add code mention in double quotes in my above code
You already have a form. What you need to change the TextField to TextFormField.
TextFormField supports the validator method.
See the complete sample at bottom of this link
https://flutter.dev/docs/cookbook/forms/validation
I'm looking to add validation to my application, but I have no idea to save the data from TextFormField and assign it to _email and _password. I'm very new to coding in Flutter....or coding at all and would really appreciate help.
Can anyone please give me some advice on what to do and get the data validated?
Here is what I have so far, but I cannot get any of the data from the TextFormFields into the assigned String values to use them for validation.
import 'package:flutter/material.dart';
import 'package:ursussupport/home_page.dart';
class LoginPage extends StatefulWidget {
static String tag = 'login-page';
#override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final scaffoldKey = GlobalKey<ScaffoldState>();
final formKey = GlobalKey<FormState>();
String _email;
String _password;
void _onSubmit() {
final form = formKey.currentState;
if (form.validate()) {
form.save();
// Email & password matched our validation rules
// and are saved to _email and _password fields.
_performLogin();
}
}
void _performLogin(){
Navigator.of(context).pushNamed(HomePage.tag);
}
#override
Widget build(BuildContext context) {
final logo = Hero(
tag: 'avatar',
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 90.0,
child: Image.asset('assets/niishaw2.jpg'),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: 'Enter Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
labelText: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
)
),
);
final password = TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
hintText: 'Enter 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: _performLogin,
color: Colors.lightBlueAccent,
child: Text('Login', 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: 50.0),
email,
SizedBox(height: 8.0),
password,
SizedBox(height: 24.0),
loginButton,
forgotLabel
],
) ,
),
);
}
}
You can use TextField it has a property onChanged so you can do this and it'll work perfectly for you .
Use this code sample
final email = TextField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: 'Enter Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
labelText: null,
),
onChanged: (String str){
setState((){
email = str;
});
},
);
You can simple add the above shown onChanged property in your code .