Skip to content
Related Articles

Related Articles

Flutter – OTP Input Fields

View Discussion
Improve Article
Save Article
Like Article
  • Last Updated : 08 Feb, 2022

Modern applications majorly that require OTP verification require OTP style input fields. We need to generate larger boilerplate code for creating amazing input fields. Then, the pinput package comes to the rescue. With this package, we can create customizable OTP input fields easily. Let us see its implementation in this article.

Step 1: Add the dependency

To use pinput, we need to add pinput in pubspec.yaml file of the app.

flutter pub add pinput

Step 2: Import the dependency

Import the dependency in the file where we need to create input fields.

Dart




import 'package:pinput/pin_put/pin_put.dart';


Step 3: Implementation

  • Create a Snackbar that will show a pin when the pin is submitted.

Dart




void _showSnackBar(String pin) {
    final snackBar = SnackBar(
      duration: Duration(seconds: 4),
      content: Container(
        height: 80.0,
        child: Center(
          child: Text(
            'Pin Submitted: $pin',
            style: TextStyle(fontSize: 25.0),
          ),
        ),
      ),
      backgroundColor: Colors.green,
    );
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(snackBar);
  }


  • Initialize a TextEditingController() _pinputController.

Dart




final _pinPutController = TextEditingController();


  • We can create input fields using PinPut() widget. Given below are all the properties of PinPut().

Dart




PinPut({
  Key? key,
  required int fieldsCount,
  void Function(String)? onSubmit,
  void Function(String?)? onSaved,
  void Function(String)? onChanged,
  void Function()? onTap,
  void Function(String?)? onClipboardFound,
  TextEditingController? controller,
  FocusNode? focusNode,
  Widget? preFilledWidget,
  List<int> separatorPositions = const [],
  Widget separator = const SizedBox(width: 15.0),
  TextStyle? textStyle,
  BoxDecoration? submittedFieldDecoration,
  BoxDecoration? selectedFieldDecoration,
  BoxDecoration? followingFieldDecoration,
  BoxDecoration? disabledDecoration,
  double? eachFieldWidth,
  double? eachFieldHeight,
  MainAxisAlignment fieldsAlignment = MainAxisAlignment.spaceBetween,
  AlignmentGeometry eachFieldAlignment = Alignment.center,
  EdgeInsetsGeometry? eachFieldMargin,
  EdgeInsetsGeometry? eachFieldPadding,
  BoxConstraints eachFieldConstraints = const BoxConstraints(minHeight: 40.0,
                                                             minWidth: 40.0),
  InputDecoration? inputDecoration,
  Curve animationCurve = Curves.linear,
  Duration animationDuration = const Duration(milliseconds: 160),
  PinAnimationType pinAnimationType = PinAnimationType.slide,
  Offset? slideTransitionBeginOffset,
  bool enabled = true,
  bool checkClipboard = false,
  bool useNativeKeyboard = true,
  bool autofocus = false,
  AutovalidateMode autovalidateMode = AutovalidateMode.disabled,
  bool withCursor = false,
  Widget? cursor,
  Brightness? keyboardAppearance,
  List<TextInputFormatter>? inputFormatters,
  String? Function(String?)? validator,
  TextInputType keyboardType = TextInputType.number,
  String? obscureText,
  TextCapitalization textCapitalization = TextCapitalization.none,
  TextInputAction? textInputAction,
  ToolbarOptions? toolbarOptions = const ToolbarOptions(paste: true),
  MainAxisSize mainAxisSize = MainAxisSize.max,
  Iterable<String>? autofillHints,
  bool enableIMEPersonalizedLearning = true,
  String? initialValue,
  SmartDashesType? smartDashesType,
  SmartQuotesType? smartQuotesType,
  bool enableSuggestions = true,
  MaxLengthEnforcement? maxLengthEnforcement,
  void Function()? onEditingComplete,
  double cursorWidth = 2,
  double? cursorHeight,
  Radius? cursorRadius,
  Color? cursorColor,
  bool enableInteractiveSelection = true,
  TextSelectionControls? selectionControls,
  Widget? Function(BuildContext, {required int currentLength,
                                  required bool isFocused,
                                  required int? maxLength})? buildCounter,
  String? restorationId
  })


Let us see two different styles of input fields through examples.

DarkRounded Fields:

Dart




Widget darkRoundedPinPut() {
    return PinPut(
      eachFieldWidth: 50.0,
      eachFieldHeight: 50.0,
      withCursor: true,
      fieldsCount: 5,
      controller: _pinPutController,
      eachFieldMargin: EdgeInsets.symmetric(horizontal: 10),
      onSubmit: (String pin) => _showSnackBar(pin),
      submittedFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      selectedFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      followingFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      pinAnimationType: PinAnimationType.rotation,
      textStyle: TextStyle(color: Colors.white,
                           fontSize: 20.0,
                           height: 1),
    );
  }


Output:

Fields with AnimatedBorder:

Dart




Widget animatedBorders() {
  return Padding(
    padding: const EdgeInsets.all(8.0),
    child: PinPut(
      fieldsCount: 4,
      eachFieldHeight: 50.0,
      withCursor: true,
      onSubmit: (String pin) => _showSnackBar(pin),
      controller: _pinPutController,
      submittedFieldDecoration: BoxDecoration(
        border: Border.all(color: Colors.black),
        borderRadius: BorderRadius.circular(15.0),
      ).copyWith(
        borderRadius: BorderRadius.circular(20.0),
      ),
      selectedFieldDecoration: BoxDecoration(
        color: Colors.green,
        border: Border.all(color: Colors.black),
        borderRadius: BorderRadius.circular(15.0),
      ),
      followingFieldDecoration: BoxDecoration(
        border: Border.all(color: Colors.black),
        borderRadius: BorderRadius.circular(15.0),
      ).copyWith(
        borderRadius: BorderRadius.circular(5.0),
        border: Border.all(
          color: Colors.black,
        ),
      ),
    ),
  );
}


Output:

Full Source Code:

Dart




import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';
  
void main() => runApp(MyApp());
  
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.green),
      home: PinPutView(),
    );
  }
}
  
class PinPutView extends StatefulWidget {
  @override
  PinPutViewState createState() => PinPutViewState();
}
  
class PinPutViewState extends State<PinPutView> {
  final _pinPutController = TextEditingController();
  final _pinPutController2 = TextEditingController();
  
  @override
  void initState() {
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("GeeksForGeeks"),
          centerTitle: true,
        ),
        body: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Expanded(child: darkRoundedPinPut()),
                Expanded(child: animatedBorders())
              ]),
        ));
  }
  
  Widget darkRoundedPinPut() {
    return PinPut(
      eachFieldWidth: 50.0,
      eachFieldHeight: 50.0,
      withCursor: true,
      fieldsCount: 5,
      controller: _pinPutController,
      eachFieldMargin: EdgeInsets.symmetric(horizontal: 10),
      onSubmit: (String pin) => _showSnackBar(pin),
      submittedFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      selectedFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      followingFieldDecoration: BoxDecoration(
        color: Colors.green[800],
        borderRadius: BorderRadius.circular(15.0),
      ),
      pinAnimationType: PinAnimationType.rotation,
      textStyle: TextStyle(color: Colors.white,
                           fontSize: 20.0,
                           height: 1),
    );
  }
  
  Widget animatedBorders() {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: PinPut(
        fieldsCount: 4,
        eachFieldHeight: 50.0,
        withCursor: true,
        onSubmit: (String pin) => _showSnackBar(pin),
        controller: _pinPutController2,
        submittedFieldDecoration: BoxDecoration(
          border: Border.all(color: Colors.black),
          borderRadius: BorderRadius.circular(15.0),
        ).copyWith(
          borderRadius: BorderRadius.circular(20.0),
        ),
        selectedFieldDecoration: BoxDecoration(
          color: Colors.green,
          border: Border.all(color: Colors.black),
          borderRadius: BorderRadius.circular(15.0),
        ),
        followingFieldDecoration: BoxDecoration(
          border: Border.all(color: Colors.black),
          borderRadius: BorderRadius.circular(15.0),
        ).copyWith(
          borderRadius: BorderRadius.circular(5.0),
          border: Border.all(
            color: Colors.black,
          ),
        ),
      ),
    );
  }
  
  void _showSnackBar(String pin) {
    final snackBar = SnackBar(
      duration: Duration(seconds: 4),
      content: Container(
        height: 80.0,
        child: Center(
          child: Text(
            'Pin Submitted: $pin',
            style: TextStyle(fontSize: 25.0),
          ),
        ),
      ),
      backgroundColor: Colors.green,
    );
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(snackBar);
  }
}


Output:


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!