Flutter – OTP Input Fields
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( "w3wiki" ), 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:
Contact Us