pin_code_fields 7.0.0-nullsafety pin_code_fields: ^7.0.0-nullsafety copied to clipboard
A flutter package which will help you to generate pin code fields. Can be useful for OTP for example.
import 'dart:async';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import './constants/constants.dart';
void main() => runApp(MyApp());
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,
backgroundColor: Colors.white,
scaffoldBackgroundColor: Colors.white,
),
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> {
TextEditingController textEditingController = TextEditingController();
// ..text = "123456";
// ignore: close_sinks
StreamController<ErrorAnimationType>? errorController;
bool hasError = false;
String currentText = "";
final formKey = GlobalKey<FormState>();
@override
void initState() {
errorController = StreamController<ErrorAnimationType>();
super.initState();
}
@override
void dispose() {
errorController!.close();
super.dispose();
}
// snackBar Widget
snackBar(String? message) {
return ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message!),
duration: Duration(seconds: 2),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Constants.PRIMARY_COLOR,
body: GestureDetector(
onTap: () {},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView(
children: <Widget>[
SizedBox(height: 30),
Container(
height: MediaQuery.of(context).size.height / 3,
child: ClipRRect(
borderRadius: BorderRadius.circular(30),
child: Image.asset("${Constants.OTP_GIF_IMAGE}"),
),
),
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,
),
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Colors.green.shade600,
fontWeight: FontWeight.bold,
),
length: 6,
obscureText: true,
obscuringCharacter: '*',
obscuringWidget: FlutterLogo(
size: 24,
),
blinkWhenObscuring: true,
animationType: AnimationType.fade,
validator: (v) {
if (v!.length < 3) {
return "I'm from validator";
} else {
return null;
}
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
fieldWidth: 40,
activeFillColor:
hasError ? Colors.blue.shade100 : Colors.white,
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
enableActiveFill: true,
errorAnimationController: errorController,
controller: textEditingController,
keyboardType: TextInputType.number,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) {
print("Completed");
},
// onTap: () {
// print("Pressed");
// },
onChanged: (value) {
print(value);
setState(() {
currentText = value;
});
},
beforeTextPaste: (text) {
print("Allowing to paste $text");
//if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
//but you can show anything you want here, like your pop up saying wrong paste format or etc
return true;
},
)),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError ? "*Please fill up all the cells properly" : "",
style: TextStyle(
color: Colors.red,
fontSize: 12,
fontWeight: FontWeight.w400),
),
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Didn't receive the code? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
),
TextButton(
onPressed: () => snackBar("OTP resend!!"),
child: Text(
"RESEND",
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: TextButton(
onPressed: () {
formKey.currentState!.validate();
// conditions for validating
if (currentText.length != 6 || currentText != "123456") {
errorController!.add(ErrorAnimationType
.shake); // Triggering error shake animation
setState(() {
hasError = true;
});
} else {
setState(
() {
hasError = false;
snackBar("OTP Verified!!");
},
);
}
},
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)
]),
),
SizedBox(
height: 16,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: TextButton(
child: Text("Clear"),
onPressed: () {
textEditingController.clear();
},
)),
Flexible(
child: TextButton(
child: Text("Set Text"),
onPressed: () {
setState(() {
textEditingController.text = "123456";
});
},
)),
],
)
],
),
),
),
);
}
}