Create reusable password field in flutter with preview check
It took 4 days search to find this, so I'm sharing it with the community, credit goes to X-Wei.
Problem:
Creating a password field in flutter with preview check as below:
Solution:
- Define
StatefulWidget
to for a newwidget
namedPasswordField
as below:
class PasswordField extends StatefulWidget { const PasswordField({ }); _PasswordFieldState createState() => new _PasswordFieldState();
} class _PasswordFieldState extends State<PasswordField> { Widget build(BuildContext context) { return TextFormField( );
}
- Define the required
widget
parameter in theStatefulWidget
class above, as below:
const PasswordField({ this.fieldKey, this.maxLength, this.hintText, this.labelText, this.helperText, this.onSaved, this.validator, this.onFieldSubmitted, }); final Key fieldKey; final int maxLength; final String hintText; final String labelText; final String helperText; final FormFieldSetter<String> onSaved; final FormFieldValidator<String> validator; final ValueChanged<String> onFieldSubmitted;
In the widget State
return a TextFormField
that has a decoration: InputDecoration
In the decoration: InputDecoration
define a suffixIcon: GestureDetector
that has a child: Icon
and onTap
function that change the state, like below:
suffixIcon: GestureDetector( onTap: () { setState(() { _obscureText = !_obscureText; }); }, child: Icon(_obscureText ? Icons.visibility : Icons.visibility_off), ),
- So, the full
StatefulWidget
of ourPasswordField
, became as belowpassword.dart
:
import 'package:flutter/material.dart'; class PasswordField extends StatefulWidget { const PasswordField({ this.fieldKey, this.maxLength, this.hintText, this.labelText, this.helperText, this.onSaved, this.validator, this.onFieldSubmitted, }); final Key fieldKey; final int maxLength; final String hintText; final String labelText; final String helperText; final FormFieldSetter<String> onSaved; final FormFieldValidator<String> validator; final ValueChanged<String> onFieldSubmitted; _PasswordFieldState createState() => _PasswordFieldState();
} class _PasswordFieldState extends State<PasswordField> { bool _obscureText = true; Widget build(BuildContext context) { return TextFormField( key: widget.fieldKey, obscureText: _obscureText, maxLength: widget.maxLength ?? 8, onSaved: widget.onSaved, validator: widget.validator, onFieldSubmitted: widget.onFieldSubmitted, decoration: InputDecoration( border: const UnderlineInputBorder(), filled: true, hintText: widget.hintText, labelText: widget.labelText, helperText: widget.helperText, suffixIcon: GestureDetector( onTap: () { setState(() { _obscureText = !_obscureText; }); }, child: Icon(_obscureText ? Icons.visibility : Icons.visibility_off), ), ), ); }
}
- Call this widget in your screen as any other widget, just like:
child: PasswordField( ),
- Before calling this child, you need to define the below:
String _password; final _passwordFieldKey = GlobalKey<FormFieldState<String>>();
- The full code to call it, can be as:
import 'package:flutter/material.dart';
import 'package:myApp/password.dart'; class LoginPage extends StatefulWidget { _LoginPageState createState() => new _LoginPageState();
} class _LoginPageState extends State<LoginPage> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); String _email, _password; final _passwordFieldKey = GlobalKey<FormFieldState<String>>(); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Form( key: _formKey, child: Column( children: <Widget>[TextFormField( validator: (input) { if(input.isEmpty){ return 'Provide an email'; } }, decoration: InputDecoration( labelText: 'Email' ), onSaved: (input) => _email = input, ), PasswordField( fieldKey: _passwordFieldKey, helperText: 'No more than 8 characters.', labelText: 'Password *', onSaved: (input) => _password = input, ), SizedBox(height: 24.0), RaisedButton( onPressed: signIn, child: Text('Sign in'), ),], ) ), ); } void signIn() async { if(_formKey.currentState.validate()){ _formKey.currentState.save(); print("email: $_email, password: $_password"); } }
}