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



Different Shapes



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