Sign in
Log inSign up
Create reusable password field in flutter with preview check

Create reusable password field in flutter with preview check

Hasan Yousef's photo
Hasan Yousef
·Jan 7, 2019

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:

psswrd.png

Solution:

  • Define StatefulWidget to for a new widget named PasswordField as below:
class PasswordField extends StatefulWidget {
  const PasswordField({
  });

  @override
  _PasswordFieldState createState() => new _PasswordFieldState();
}

class _PasswordFieldState extends State<PasswordField> {

  @override
  Widget build(BuildContext context) {
  return TextFormField(
  );
}
  • Define the required widget parameter in the StatefulWidget 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 our PasswordField, became as below password.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;

  @override
  _PasswordFieldState createState() => _PasswordFieldState();
}

class _PasswordFieldState extends State<PasswordField> {
  bool _obscureText = true;

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      key: widget.fieldKey,
      obscureText: _obscureText,
      maxLength: widget.maxLength ?? 8,  // if not provided by the user, then it is 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 {
  @override
  _LoginPageState createState() => new _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {

  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  String _email, _password;
  final _passwordFieldKey = GlobalKey<FormFieldState<String>>();

  @override
  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");
    }
  }
}