in , , ,

A flutter package that will help you to generate pin code fields

pin_code_fields

With its beautiful design and smart interface, it is easy to use. A flutter package that aids in the creation of pin code fields.  It can be useful for OTP or pin code inputs.

In this detailed tutorial, we are going to learn to create the text fields that hide the user-entered value as a Pin. This Flutter Pin Input Text Field is used for users to enter the input values. The pin code is unique or specific to the particular user. Besides, we can even create different types of pin input text fields in Flutter.

Features

Here are some of its salient features.

  • Automatically focuses the next field on typing and focuses previous field on deletation
  • Can be set to any length. (3-6 fields recommended)
  • 3 different shapes for text fields
  • Highly customizable
  • 3 different types of animation for input texts
  • Animated active, inactive field color switching
  • Autofocus option
  • Otp-code pasting from clipboard
  • iOS autofill support
  • Get currently typed text and use your condition to validate it. (for example: if (currentText.length != 6 || currentText != “<your desired code>“))

Properties

/// length of how many cells there should be. 4-6 is recommended by me
final int length;

/// you already know what it does i guess :P default is false
final bool obsecureText;

/// returns the current typed text in the fields
final ValueChanged<String> currentText;

/// this defines the shape of the input fields. Default is underlined
final PinCodeFieldShape shape;

/// the style of the text, default is [ fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold]
final TextStyle textStyle;

/// background color for the whole row of pin code fields. Default is [Colors.white]
final Color backgroundColor;

/// Border radius of each pin code field
final BorderRadius borderRadius;

/// [height] for the pin code field. default is [50.0]
final double fieldHeight;

/// [width] for the pin code field. default is [40.0]
final double fieldWidth;

/// If the pin code field should be autofocused or not. Default is [false]
final bool autoFocus;

/// This defines how the elements in the pin code field align. Default to [MainAxisAlignment.spaceBetween]
final MainAxisAlignment mainAxisAlignment;

/// Colors of the input fields which have inputs. Default is [Colors.green]
final Color activeColor;

/// Colors of the input fields which don't have inputs. Default is [Colors.red]
final Color inactiveColor;

/// Border width for the each input fields. Default is [2.0]
final double borderWidth;

/// [AnimationType] for the text to appear in the pin code field. Default is [AnimationType.slide]
final AnimationType animationType;

/// Duration for the animation. Default is [Duration(milliseconds: 150)]
final Duration animationDuration;

/// [Curve] for the animation. Default is [Curves.easeInOut]
final Curve animationCurve;

/// [TextInputType] for the pin code fields. default is [TextInputType.visiblePassword]
final TextInputType textInputType;

Flare animation credit: https://www.2dimensions.com/a/atiq31416/files/flare/otp-verification/preview

Getting Started

Demo

pin_code
android_paste
ios_pasting

Different Shapes

pic1
pic2
pic3

The pin code text field widget example

PinCodeTextField(
  length: 6,
  obsecureText: false,
  animationType: AnimationType.fade,
  shape: PinCodeFieldShape.box,
  animationDuration: Duration(milliseconds: 300),
  borderRadius: BorderRadius.circular(5),
  fieldHeight: 50,
  fieldWidth: 40,
  currentText: (value) {
    setState(() {
      currentText = value;
    });
  },
)

Shape can be among these 3 types

enum PinCodeFieldShape { box, underline, circle }

Animations can be among these 3 types

enum AnimationType { scale, slide, fade, none }

This full code is from the example folder. You can run the example to see.

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,
      ),
      home: PinCodeVerificationScreen(
          "+8801376221100"), // a random number, please don't call xD
    );
  }
}

class PinCodeVerificationScreen extends StatefulWidget {
  final String phoneNumber;
  PinCodeVerificationScreen(this.phoneNumber);
  @override
  _PinCodeVerificationScreenState createState() =>
      _PinCodeVerificationScreenState();
}

class _PinCodeVerificationScreenState extends State<PinCodeVerificationScreen> {
  var onTapRecognizer;

  /// this [StreamController] will take input of which function should be called

  bool hasError = false;
  String currentText = "";
  final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  @override
  void initState() {
    onTapRecognizer = TapGestureRecognizer()
      ..onTap = () {
        Navigator.pop(context);
      };

    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      body: GestureDetector(
        onTap: () {
          FocusScope.of(context).requestFocus(new FocusNode());
        },
        child: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: ListView(
            children: <Widget>[
              SizedBox(height: 30),
              Image.asset(
                'assets/verify.png',
                height: MediaQuery.of(context).size.height / 3,
                fit: BoxFit.fitHeight,
              ),
              SizedBox(height: 8),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: Text(
                  'Phone Number Verification',
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
                  textAlign: TextAlign.center,
                ),
              ),
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: 30.0, vertical: 8),
                child: RichText(
                  text: TextSpan(
                      text: "Enter the code sent to ",
                      children: [
                        TextSpan(
                            text: widget.phoneNumber,
                            style: TextStyle(
                                color: Colors.black,
                                fontWeight: FontWeight.bold,
                                fontSize: 15)),
                      ],
                      style: TextStyle(color: Colors.black54, fontSize: 15)),
                  textAlign: TextAlign.center,
                ),
              ),
              SizedBox(
                height: 20,
              ),
              Padding(
                  padding:
                      const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30),
                  child: PinCodeTextField(
                    length: 6,
                    obsecureText: false,
                    animationType: AnimationType.fade,
                    shape: PinCodeFieldShape.underline,
                    animationDuration: Duration(milliseconds: 300),
                    borderRadius: BorderRadius.circular(5),
                    fieldHeight: 50,
                    fieldWidth: 40,
                    currentText: (value) {
                      setState(() {
                        currentText = value;
                      });
                    },
                  )),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 30.0),
                // error showing widget
                child: Text(
                  hasError ? "*Please fill up all the cells properly" : "",
                  style: TextStyle(color: Colors.red.shade300, fontSize: 15),
                ),
              ),
              SizedBox(
                height: 20,
              ),
              RichText(
                textAlign: TextAlign.center,
                text: TextSpan(
                    text: "Didn't receive the code? ",
                    style: TextStyle(color: Colors.black54, fontSize: 15),
                    children: [
                      TextSpan(
                          text: " RESEND",
                          recognizer: onTapRecognizer,
                          style: TextStyle(
                              color: Color(0xFF91D3B3),
                              fontWeight: FontWeight.bold,
                              fontSize: 16))
                    ]),
              ),
              SizedBox(
                height: 14,
              ),
              Container(
                margin:
                    const EdgeInsets.symmetric(vertical: 16.0, horizontal: 30),
                child: ButtonTheme(
                  height: 50,
                  child: FlatButton(
                    onPressed: () {
                      // conditions for validating
                      if (currentText.length != 6 || currentText != "towtow") {
                        setState(() {
                          hasError = true;
                        });
                      } else {
                        setState(() {
                          hasError = false;
                          scaffoldKey.currentState.showSnackBar(SnackBar(
                            content: Text("Aye!!"),
                            duration: Duration(seconds: 2),
                          ));
                        });
                      }
                    },
                    child: Center(
                        child: Text(
                      "VERIFY".toUpperCase(),
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 18,
                          fontWeight: FontWeight.bold),
                    )),
                  ),
                ),
                decoration: BoxDecoration(
                    color: Colors.green.shade300,
                    borderRadius: BorderRadius.circular(5),
                    boxShadow: [
                      BoxShadow(
                          color: Colors.green.shade200,
                          offset: Offset(1, -2),
                          blurRadius: 5),
                      BoxShadow(
                          color: Colors.green.shade200,
                          offset: Offset(-1, 2),
                          blurRadius: 5)
                    ]),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

GitHub

https://github.com/adar2378/pin_code_fields

Written by James

PIN input field widget for Flutter with paste from clipboard functionality

An amazing password strength checker for flutter