How to Build an OTP Verification Screen in Flutter with GetX: Complete Guide with Beautified UI
Creating an OTP (One-Time Password) verification screen is a crucial part of many apps for security purposes. In this post, we’ll guide you through setting up a modern OTP verification screen in Flutter using GetX for state management. We'll also provide a beautiful UI that resembles the design shared.
Step 1: Add Dependencies
Add the necessary dependencies in your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
get: ^4.6.5
pin_code_fields: ^7.4.0
Run flutter pub get
to fetch the packages.
Step 2: Create the OTP Controller with GetX
We’ll create a controller that manages the timer, OTP input, and validation.
otp_controller.dart
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'dart:async';
class OTPController extends GetxController {
var isCodeExpired = false.obs;
var otp = ''.obs;
var remainingTime = 60.obs; // 1 minute in seconds
Timer? timer;
TextEditingController otpController = TextEditingController(); // Create a TextEditingController
@override
void onInit() {
startTimer();
super.onInit();
}
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (remainingTime.value > 0) {
remainingTime.value--;
} else {
isCodeExpired.value = true;
timer.cancel();
}
});
}
void resendCode() {
remainingTime.value = 60; // Reset timer to 60 seconds
isCodeExpired.value = false;
otp.value = ''; // Clear the OTP field in the controller
otpController.clear(); // Clear the text fields in PinCodeTextField
startTimer(); // Restart the timer
update(); // Notify UI to update
}
void onOTPComplete(String value) {
otp.value = value;
}
@override
void onClose() {
timer?.cancel();
otpController.dispose(); // Dispose of the controller
super.onClose();
}
}
Step 3: Create the Beautified OTP Verification UI
We'll design the UI similar to the one you shared with a countdown timer, input fields for the OTP, and a "Resend Code" option.
otp_view.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:getx_tutorials/widgets/custom_button/custom_button.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:sizer/sizer.dart';
import '../widgets/app_color/app_color.dart';
import '../widgets/app_image/app_image.dart';
import 'otp_controller.dart';
class OtpVerificationScreen extends GetView {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgPicture.asset(
AppImages.scanIcon,
height: 65.0, // Adjust the size of the icon if necessary
width: 65.0,
), // Add your logo here
const SizedBox(height: 20),
Text(
'OTP Verification',
style: GoogleFonts.poppins(
fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text(
'We have sent an OTP on given number +91 2224 555 333',
textAlign: TextAlign.center,
style: GoogleFonts.poppins(fontSize: 16, color: Colors.grey),
),
const SizedBox(height: 20),
Obx(() {
return Text(
controller.isCodeExpired.value
? "Your otp has expired please resend"
: "00:${controller.remainingTime.value.toString().padLeft(2, '0')}",
style: GoogleFonts.poppins(
color: controller.isCodeExpired.value
? AppColors.appColor
: AppColors.appColor,
fontSize: 18,
),
);
}),
SizedBox(height: 4.h),
PinCodeTextField(
appContext: context,
length: 4,
onChanged: (value) {
controller.update();
},
onCompleted: controller.onOTPComplete,
controller: controller.otpController,
autoDismissKeyboard: true,
enablePinAutofill: true,
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(15),
fieldHeight: 75,
fieldWidth: 75,
activeColor: AppColors.appColor,
activeFillColor: AppColors.appbarColor,
selectedColor: AppColors.appColor,
selectedFillColor: AppColors.btnColor,
inactiveColor: Colors.grey,
),
),
const SizedBox(height: 20),
const SizedBox(height: 20),
Obx(
() => CustomButton(
onPressed: controller.resendCode,
backgroundColor: controller.otp.value.length == 4
? AppColors.appColor
: controller.isCodeExpired.value
? AppColors.appColor
: AppColors.btnColor,
text:
controller.isCodeExpired.value ? "Send Code Again" : 'Next',
image: AppImages.rightArrow,
imageColor: controller.isCodeExpired.value
? AppColors.white
: controller.otp.value.length == 4
? AppColors.whiteColor
: AppColors.optionIconColor,
color: controller.isCodeExpired.value
? AppColors.white
: controller.otp.value.length == 4
? AppColors.whiteColor
: AppColors.optionIconColor,
),
)
],
),
),
);
}
}
Step 4: Binding the Controller
Bind the OTPController
to the view using GetX bindings.
otp_binding.dart
import 'package:get/get.dart';
import 'otp_controller.dart';
class OtpVerificationBindings extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => OTPController());
}
}
Step 5: Main Application Setup
In your main.dart
, configure the routes and bindings using GetX.
main.dart
import 'package:flutter/material.dart';
import 'package:get/get_navigation/src/root/get_material_app.dart';
import 'package:getx_tutorials/widgets/app_color/app_color.dart';
import 'package:getx_tutorials/widgets/app_routes/app_routes.dart';
import 'package:responsive_framework/responsive_wrapper.dart';
import 'package:responsive_framework/utils/scroll_behavior.dart';
import 'package:sizer/sizer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
Map color = {
50: const Color(0xFF7DEF83),
100: const Color(0xFF7DEF83),
200: const Color(0xFF7DEF83),
300: const Color(0xFF7DEF83),
400: const Color(0xFF7DEF83),
500: const Color(0xFF7DEF83),
600: const Color(0xFF7DEF83),
700: const Color(0xFF7DEF83),
800: const Color(0xFF7DEF83),
900: const Color(0xFF7DEF83),
};
return Sizer(
builder: (context, orientation, deviceType) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
title: 'EV Assert',
theme: ThemeData(
primarySwatch: MaterialColor(0xFFA4573B, color),
splashColor: AppColors.appColor,
highlightColor: AppColors.appColor,
),
// home: OnboardingScreen(),
builder: (context, child) => ResponsiveWrapper.builder(
BouncingScrollWrapper.builder(context, child!),
maxWidth: 1400,
minWidth: 450,
defaultScale: true,
breakpoints: [
const ResponsiveBreakpoint.resize(450, name: MOBILE),
const ResponsiveBreakpoint.autoScale(800, name: TABLET),
const ResponsiveBreakpoint.autoScale(1000, name: TABLET),
const ResponsiveBreakpoint.resize(1200, name: DESKTOP),
const ResponsiveBreakpoint.autoScale(2460, name: "4K"),
],
background: Container(color: const Color(0xFFF5F5F5))),
// initialBinding: BindingsBuilder(() {
// printAction("Data coming here");
// }),
initialRoute: AppRoutes.otpScreen,
getPages: AppRoutes.pages,
);
},
);
}
}
This complete example demonstrates how to implement a functional and beautiful OTP verification screen in Flutter using GetX. The interface includes features like a countdown timer, OTP input field, and the ability to resend the code if it expires.
By following this guide, you can easily integrate a professional OTP verification system into your Flutter app with a modern and clean UI.
0 Comments
Please Do Not Comments Any Span Or Span link..