Flutter Animation: How to Create Registration Screen for Password Verification in Android & iOS App?

Password-verification-using-flutter-animation

In this tutorial, we have included information for those tech startups, which are trying to create registration screen with password verification in Android or iOS application. Here, we have explained how password criteria is being verified using Flutter animation by following some simple steps while creating a registration screen. Let’s get started with it.

A text field is a field, where users enter text such as name, email, password, etc. It takes input from users in the form of plain text, numeric, or special character.
In order to enter data within the text field, it’s users need to tap on the placeholder to open the keyboard to write anything.

Objective

In this Android app tutorial, we have created a strikethrough animation to check password verification at the time of registration. To give some hint about the required password criteria, we have provided one of the features of Textfield.

This demo for password criteria verification with flutter animation in Android is being created using Dart programming language (Flutter Framework ver. 1.0).

Let’s Get Started

Here’re the steps to implement password verification (at the time of user registration) using flutter when developing an Android or iOS app that requires user registration.

Step 1: First of all, create your flutter project (we are using Android Studio)

flutter project

 

Step 2: Then, insert your project name and provide flutter SDK path

configure flutter application

set package name

 

Step 3: Let’s build the UI first

Container(
 decoration: BoxDecoration(
   color: Colors.white
 ),
 child: SingleChildScrollView(
   child:ConstrainedBox(
       constraints: BoxConstraints(
           maxHeight: deviceHeight,
   ),
   child: Column(
     children: [
       SizedBox(
           height: 50,
       ),
       Container(
           child: renderValidation()),
       Container(
         height: 50,width: 100,
       ),
       Container(
         child: Column(
           children: [
             Padding(
               padding: const EdgeInsets.all(15.0),
               child: TextField(
                 controller: textController,
                 style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,letterSpacing: 1),
                 decoration: InputDecoration(
                     hintText: 'Enter the password',
                     filled: true,
                     border: InputBorder.none,
                     fillColor: Colors.indigoAccent,
                  ),
               ),
             )
           ],
         ),
       )
     ],
   ),
 ),
 )
);

Step 4:
Create renderValidation() function. It is responsible for the Field Container rendering.
Here, we have created one small widget called _renderLine() for rendering the bottom line for margin purpose.

 Widget _renderLine() {
   return Container(
     height: 1,
     decoration: BoxDecoration(color: Colors.grey),
   );
 }

 renderValidation() {
   return Stack(
     children: [
       Padding(
         padding: const EdgeInsets.all(15.0),
         child: Card(
             elevation: 0,
             child: Stack(
               alignment: Alignment.bottomLeft,
               children: [
                 Column(
                   crossAxisAlignment: CrossAxisAlignment.start,
                   mainAxisSize: MainAxisSize.min,
                   children: [
                     ValidationItem("1 special character", oneSpecialChar),
                     _renderLine(),
                     ValidationItem("1 numeric", requiredAt),
                     _renderLine(),
                     ValidationItem("8 character", eightChar),
                   ],
                 ),
               ],
             )),
       ),
     ],
   );
 }
}

Step 5: Creating individual fields
Now, we will create one more class called ValidationItem just for rendering fields as it takes Params like the title and valid status.

Code : main.dart

import 'package:first_app/validatationField.dart';
import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';

void main() {

 runApp(new MyApp());
}

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return new MaterialApp(
     theme: new ThemeData(
       primarySwatch: Colors.teal,
     ),
     debugShowCheckedModeBanner: false,
     home: new Scaffold(
       appBar: AppBar(
         title: Text('Enter the password'),
       ),
       backgroundColor: Colors.white,
       body: new MyReviewPage(),
     ),
   );
 }
}

class MyReviewPage extends StatefulWidget {
 MyReviewPage({Key key}) : super(key: key);

 @override
 _MyReviewPageState createState() => new _MyReviewPageState();
}


class _MyReviewPageState extends State
   with TickerProviderStateMixin {
 TextEditingController textController = TextEditingController();
 AnimationController _controller;
 Animation _fabScale;

 var eightChar = false,
     oneSpecialChar=false,
     requiredAt=false  ;

 @override
 void initState() {
   // TODO: implement initState
   super.initState();
   textController.addListener(() {
     setState(() {
       eightChar = textController.text.length > 8;
       oneSpecialChar=textController.text.isNotEmpty &&
           !textController.text.contains(RegExp(r'^[\w&.-]+$'), 0);
       requiredAt=textController.text.contains(RegExp(r'\d'), 0);
     });
   });

   _controller = new AnimationController(
       vsync: this, duration: const Duration(microseconds: 500));

   _fabScale = Tween(begin: 0, end: 1)
       .animate(CurvedAnimation(parent: _controller, curve: Curves.bounceOut));

   _fabScale.addListener(() {
     setState(() {});
   });
   if (_allValid()) {
     _controller.forward();
   } else {
     _controller.reverse();
   }
 }

 bool _allValid() {
   return eightChar;

 }

 @override
 Widget build(BuildContext context) {
   var deviceHeight=MediaQuery.of(context).size.height;
   // TODO: implement build
   return Container(

     decoration: BoxDecoration(
       color: Colors.white
     ),
     child: SingleChildScrollView(
       child:ConstrainedBox(
           constraints: BoxConstraints(
               maxHeight: deviceHeight,
       ),
       child: Column(
         children: [
           SizedBox(
               height: 50,
           ),
           Container(
               child: renderValidation()),
           Container(
             height: 50,width: 100,
           ),
           Container(
             child: Column(
               children: [
                 Padding(
                   padding: const EdgeInsets.all(15.0),
                   child: TextField(
                     controller: textController,
                     style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,letterSpacing: 1),
                     decoration: InputDecoration(

                         hintText: 'Enter the password',
                         filled: true,
                         border: InputBorder.none,
                         fillColor: Colors.indigoAccent,
                      ),
                   ),
                 )
               ],
             ),
           )
         ],
       ),
     ),
     )
   );
 }

 Widget _renderLine() {
   return Container(
     height: 1,
     decoration: BoxDecoration(color: Colors.grey),
   );
 }

 renderValidation() {
   return Stack(
     children: [
       Padding(
         padding: const EdgeInsets.all(15.0),
         child: Card(
             elevation: 0,
             child: Stack(
               alignment: Alignment.bottomLeft,
               children: [
                 Column(
                   crossAxisAlignment: CrossAxisAlignment.start,
                   mainAxisSize: MainAxisSize.min,
                   children: [
                     ValidationItem("1 special character", oneSpecialChar),
                     _renderLine(),
                     ValidationItem("1 numeric", requiredAt),
                     _renderLine(),
                     ValidationItem("8 character", eightChar),
                   ],
                 ),
               ],
             )),
       ),
     ],
   );
 }
}

2. validationField.dart

import 'package:flutter/material.dart';

class ValidationItem extends StatefulWidget{
 ValidationItem(this.title, this.valid);

 final String title;
 final bool valid;

 @override
 _ValidationItemState createState() => _ValidationItemState();

}

class _ValidationItemState extends State with TickerProviderStateMixin{
 AnimationController _controller;
 AnimationController _animatedStrike;
 Animation _animatedWidth;
 Animation _animStrikeWidthAnim;

 @override
 void didUpdateWidget(ValidationItem oldWidget) {
   // TODO: implement didUpdateWidget
   super.didUpdateWidget(oldWidget);

   if (oldWidget.valid != widget.valid) {
     if (widget.valid) {
       __startAnimation(true);
     } else {
       __startAnimation(false);
     }
   }
 }
 @override
 void initState() {
   // TODO: implement initState
   super.initState();
   _controller=AnimationController(
       vsync: this,duration: const Duration(milliseconds: 400));

   _animatedStrike = AnimationController(
       vsync: this, duration: const Duration(milliseconds: 400));

   _animatedWidth = Tween(begin: 8, end: 12)
       .animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));

   _animStrikeWidthAnim = Tween(begin: 0, end: 1).animate(
       CurvedAnimation(parent: _animatedStrike, curve: Curves.easeOut));

   _animatedWidth.addListener(() {
     setState(() {});
   });

   _animStrikeWidthAnim.addListener(() {
     setState(() {});
   });
 }

 Future __startAnimation(bool animationDone) async {
   try {
     if (animationDone) {
       _animatedStrike.forward().orCancel;
     } else {
       _animatedStrike.reverse().orCancel;
     }

     await _controller.forward().orCancel;
     await _controller.reverse().orCancel;
   } on TickerCanceled {
     // the animation got canceled, probably because we were disposed
   }
 }


 @override
 Widget build(BuildContext context) {
   // TODO: implement build
   return Padding(
     padding: const EdgeInsets.all(0.0),
     child: Container(
       decoration: BoxDecoration(
         color: Colors.indigoAccent

       ),
       padding: EdgeInsets.all(10.0),
       child: Row(

         children: [
           CustomPaint(
             foregroundPainter: AnimStrikeWidth(_animStrikeWidthAnim.value),
             child: Text(widget.title,
               style: _adjustStyle(widget.valid),
             ),
           ),


         ],
       ),
     ),
   );
 }


 TextStyle _adjustStyle(bool validation) {
   return TextStyle(
       fontWeight: FontWeight.bold,
       color: (validation) ? Colors.white30 : Colors.white,
       fontSize: 18,
       decoration: null);
 }
}

class AnimStrikeWidth extends CustomPainter{
 var value;
 AnimStrikeWidth(this.value);

 @override
 void paint(Canvas canvas, Size size) {
   // TODO: implement paint
   canvas.drawRect(
     Rect.fromLTWH(0,(size.height/2), (size.width*value), 3.5),
     Paint()..color=Colors.grey
   );
 }

 @override
 bool shouldRepaint(CustomPainter oldDelegate) {
   // TODO: implement shouldRepaint
   return true;
 }

}

Step 6: Let’s check validation
We have used TextField another widget provided by flutter. With that, we need to provide a controller for input container and provide that in our TextField widget. We also created textController.

 
var eightChar = false,
   oneSpecialChar=false,
   requiredAt=false  ;

@override
void initState() {
 // TODO: implement initState
 super.initState();
 textController.addListener(() {
   setState(() {
     eightChar = textController.text.length > 8;
     oneSpecialChar=textController.text.isNotEmpty &&
         !textController.text.contains(RegExp(r'^[\w&.-]+$'), 0);
     requiredAt=textController.text.contains(RegExp(r'\d'), 0);
   });
 });

 _controller = new AnimationController(
     vsync: this, duration: const Duration(microseconds: 500));

 _fabScale = Tween(begin: 0, end: 1)
     .animate(CurvedAnimation(parent: _controller, curve: Curves.bounceOut));

 _fabScale.addListener(() {
   setState(() {});
 });
 if (_allValid()) {
   _controller.forward();
 } else {
   _controller.reverse();
 }
}

Step 7: Now using the setState() method with our ValidationItem class for triggering the strikethrough animation.

Column(
 crossAxisAlignment: CrossAxisAlignment.start,
 mainAxisSize: MainAxisSize.min,
 children: [
   ValidationItem("1 special character", oneSpecialChar),
   _renderLine(),
   ValidationItem("1 numeric", requiredAt),
   _renderLine(),
   ValidationItem("8 character", eightChar),
 ],
),

Step 8: Now, we need to create the animationController and animation objects to handle our animation into the initState method, which is called only once in the lifecycle of the flutter class.

AnimationController _controller;
AnimationController _animatedStrike;
Animation _animatedWidth;
Animation _animStrikeWidthAnim;

Let’s initialize them.
We use animationController for handling the time duration of our animation
And with that timeline, we increase the animStrikeWidthAnim from 0 to 1.

@override
void initState() {
 // TODO: implement initState
 super.initState();
 _controller=AnimationController(
     vsync: this,duration: const Duration(milliseconds: 400));

 _animatedStrike = AnimationController(
     vsync: this, duration: const Duration(milliseconds: 400));

 _animatedWidth = Tween(begin: 8, end: 12)
     .animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));

 _animStrikeWidthAnim = Tween(begin: 0, end: 1).animate(
     CurvedAnimation(parent: _animatedStrike, curve: Curves.easeOut));

 _animatedWidth.addListener(() {
   setState(() {});
 });

 _animStrikeWidthAnim.addListener(() {
   setState(() {});
 });
}

Step 9: Creating a widget UI

@override
Widget build(BuildContext context) {
 // TODO: implement build
 return Padding(
   padding: const EdgeInsets.all(0.0),
   child: Container(
     decoration: BoxDecoration(
       color: Colors.indigoAccent

     ),
     padding: EdgeInsets.all(10.0),
     child: Row(

       children: [
         CustomPaint(
           foregroundPainter: AnimStrikeWidth(_animStrikeWidthAnim.value),
           child: Text(widget.title,
             style: _adjustStyle(widget.valid),
           ),
         ),


       ],
     ),
   ),
 );
}

And custom painter class

class AnimStrikeWidth extends CustomPainter{
 var value;
 AnimStrikeWidth(this.value);

 @override
 void paint(Canvas canvas, Size size) {
   // TODO: implement paint
   canvas.drawRect(
     Rect.fromLTWH(0,(size.height/2), (size.width*value), 3.5),
     Paint()..color=Colors.grey
   );
 }

 @override
 bool shouldRepaint(CustomPainter oldDelegate) {
   // TODO: implement shouldRepaint
   return true;
 }

}

Step 10:  Check for an update.
We are using didUpdateWidget method that is another lifecycle method and called when an update happens.

@override
void didUpdateWidget(ValidationItem oldWidget) {
 // TODO: implement didUpdateWidget
 super.didUpdateWidget(oldWidget);

 if (oldWidget.valid != widget.valid) {
   if (widget.valid) {
     __startAnimation(true);
   } else {
     __startAnimation(false);
   }
 }
}

If there are any changes made by our parent call which is the main class
didUpdateWidget() method called, we simply compare old valid property with the new one and if there are changes then we trigger the animation method.

Step 11: Let’s animate

Future __startAnimation(bool animationDone) async {
 try {
   if (animationDone) {
     _animatedStrike.forward().orCancel;
   } else {
     _animatedStrike.reverse().orCancel;
   }

   await _controller.forward().orCancel;
   await _controller.reverse().orCancel;
 } on TickerCanceled {
   // the animation got canceled, probably because we were disposed
 }
}


Output (Video):

 


Conclusion

As we all know that forms are an important part of user registration, so it is useful to ensure that your users can get through them accurately and quickly.

You can download the source code for the above tutorial from Github.

P.S: If you still have any doubt or query about how to validate password verification feature in your app, then don’t worry. Feel free to contact our Android App Development team at Space-O Technologies through our contact us form.

This page was last edited on February 11th, 2019, at 7:01.
 
 

Have an App Idea?

Get your free consultation now