pin_code_fields 1.1.2
pin_code_fields: ^1.1.2 copied to clipboard
A flutter package which will help you to generate pin code fields. Can be useful for OTP for example.
pin_code_fields #
A flutter package which will help you to generate pin code fields. Can be useful for OTP or pin code inputs.
Features #
- Error handling
- Automatically focuses the next field
- Can be set to any length. (3-6 fields recommended)
- 3 different shapes for text fields
- Customizable
Getting Started #
Demo

Different Shapes
The pin code text field widget
PinCodeTextField(
length: 6, // must be greater than 0
obsecureText: false, //optional, default is false
shape: PinCodeFieldShape.round, //optional, default is underline
onDone: (String value) {
setState(() {
submittedString = value;
});
},
textStyle: TextStyle(fontWeight: FontWeight.bold), //optinal, default is TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.bold)
onErrorCheck: (bool value) {
setState(() {
hasError = value;
});
},
shouldTriggerFucntions: changeNotifier.stream,
);
ChangeNotifier will trigger the submission. If any error found then the onErrorCheck call back will return true
final changeNotifier = StreamController<Functions>();
Way to trigger the submission
changeNotifier.add(Functions.submit); // this will invoke the submission. Can be used inside onPressed of a button or from wherever you want to trigger it
Shape can be among these 3 types
enum PinCodeFieldShape { box, underline, round }
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
final changeNotifier = StreamController<Functions>();
PinCodeTextField pinCodeTextFieldWidget;
bool hasError = false;
String submittedString = "";
@override
void initState() {
onTapRecognizer = TapGestureRecognizer()
..onTap = () {
Navigator.pop(context);
};
pinCodeTextFieldWidget = PinCodeTextField(
length: 6,
obsecureText: false,
shape: PinCodeFieldShape.round,
onDone: (value) {
setState(() {
submittedString = value;
});
},
textStyle: TextStyle(fontWeight: FontWeight.bold),
onErrorCheck: (value) {
setState(() {
hasError = value;
});
},
shouldTriggerFucntions: changeNotifier.stream,
);
super.initState();
}
@override
void dispose() {
changeNotifier.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
),
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: 10),
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: pinCodeTextFieldWidget),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError
? "*Please fill up all the cells and press VERIFY again"
: "",
style: TextStyle(color: Colors.red.shade300, fontSize: 12),
),
),
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: () async {
/// check the [_onData] fucntion to understand better
changeNotifier.add(Functions
.submit); // at first we will check error on the press of the button.
},
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)
]),
),
Center(
child: Text(
submittedString,
style: TextStyle(fontSize: 18),
)),
],
),
),
),
);
}
}