In current age, Most of mobile apps have Login-Signup. So Login and Signup is needed functionality for all mobile apps. So we are trying to implement Login/Signup UI with validation and animation. It’s simple looks but attractive and useful in all apps.

You can Download Source Code via Github.

Animation

You have to add lib for animation in .yaml file.
simple_animations: ^1.3.3

FadeAnimation.dart

class FadeAnimation extends StatelessWidget {
  final double delay;
  final Widget child;

  FadeAnimation(this.delay, this.child);

  @override
  Widget build(BuildContext context) {
    final tween = MultiTrackTween([
      Track("opacity").add(Duration(milliseconds: 500), Tween(begin: 0.0, end: 1.0)),
      Track("translateY").add(
        Duration(milliseconds: 500), Tween(begin: -30.0, end: 0.0),
        curve: Curves.easeOut)
    ]);

    return ControlledAnimation(
      delay: Duration(milliseconds: (500 * delay).round()),
      duration: tween.duration,
      tween: tween,
      child: child,
      builderWithChild: (context, child, animation) => Opacity(
        opacity: animation["opacity"],
        child: Transform.translate(
          offset: Offset(0, animation["translateY"]), 
          child: child
        ),
      ),
    );
  }
}

Validation

Here we implement all validation in one file and we will use that methods in whole projects.

validation-util.dart

class ValidationUtil {
  String validateEmail(String value) {
    if (value.isEmpty) {
      return StringUtils.enterEmail;
    } else if (!RegExp(
            r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~][email protected][a-zA-Z0-9]+\.[a-zA-Z]+")
        .hasMatch(value)) {
      return StringUtils.enterValidEmail;
    }
    return null;
  }

  bool isValidEmail(String value) {
    if (value.isEmpty) {
      return false;
    } else if (!RegExp(
            r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~][email protected][a-zA-Z0-9]+\.[a-zA-Z]+")
        .hasMatch(value)) {
      return false;
    }
    return true;
  }

  String validatePassword(String value) {
    if (value.isEmpty) {
      return StringUtils.enterPassword;
    } else if (!RegExp("^.{6,30}").hasMatch(value)) {
      return StringUtils.enterValidPassword;
    }
    return null;
  }

  String validateConfirmPassword(String confirmvalue, String password) {
    if (confirmvalue.isEmpty) {
      return StringUtils.enterConfirmPassword;
    } else if (confirmvalue.compareTo(password) != 0) {
      return StringUtils.enterMatchPassword;
    }
    return null;
  }

  String validatePhoneNumberField(String value) {
    if (value.isEmpty) {
      return StringUtils.enterPhoneNumber;
    } else if (value.length < 9 && value.length > 20) {
      return StringUtils.enterValidPhoneNumber;
    }
    return null;
  }

  bool isValidPhoneNumber(String value) {
    if (value.isEmpty) {
      return false;
    } else if (value.length > 9 && value.length < 50) {
      value = value.replaceAll(new RegExp(r'[^\w\s]+'), '');
      value = value.replaceAll(' ', '');
      if (isNumeric(value)) {
        return true;
      }
      return false;
    }
    return false;
  }

  bool isNumeric(String s) {
    if (s == null) {
      return false;
    }
    return double.parse(s, (e) => null) != null;
  }

  String validateField(String value, String errorMessage) {
    if (value.isEmpty) {
      return errorMessage;
    }
    return null;
  }

  static bool validateFieldEmpty(String value) {
    if (value.isEmpty) {
      return false;
    }
    return true;
  }
}

Widgets

Here we implement Widgets for Text Fields to make attractive and simple

Widget makeInput(
      bool _validate, TextEditingController controller, String message,
      {label, obscureText = false}) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          label,
          style: TextStyle(
              fontSize: 15, fontWeight: FontWeight.w400, color: Colors.black87),
        ),
        SizedBox(
          height: 5,
        ),
        TextFormField(
          obscureText: obscureText,
          controller: controller,
          validator: (value) => _validationUtil.validateField(value, message),
          decoration: InputDecoration(
            errorText: _validate ? message : null,
            contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
            enabledBorder: OutlineInputBorder(
                borderSide: BorderSide(color: Colors.grey[400])),
            border: OutlineInputBorder(
                borderSide: BorderSide(color: Colors.grey[400])),
          ),
        ),
        SizedBox(
          height: 10,
        ),
      ],
    );
  }

Now, we can see how we can use animation with Text fields in Login and Signup . And it’s looking simple and attractive. Let’s see

SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.symmetric(horizontal: 30),
          height: MediaQuery.of(context).size.height - 100,
          width: double.infinity,
          child: Form(
            key: _formKey,
            child: Stack(children: <Widget>[
              Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      FadeAnimation(
                          1,
                          Text(
                            "Sign in",
                            style: TextStyle(
                                fontSize: 30, fontWeight: FontWeight.bold),
                          )),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      FadeAnimation(
                          1.2,
                          makeInput(_validateUserName, _textUserName,
                              'Please enter Username',
                              label: "Username")),
                      FadeAnimation(
                          1.3,
                          makeInput(_validatePassword, _textPassword,
                              'Please enter Password',
                              label: "Password", obscureText: true)),
                    ],
                  ),
                  FadeAnimation(
                      1.4,
                      Container(
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(10),
                            border: Border(
                              bottom: BorderSide(color: Colors.black),
                              top: BorderSide(color: Colors.black),
                              left: BorderSide(color: Colors.black),
                              right: BorderSide(color: Colors.black),
                            )),
                        child: MaterialButton(
                          minWidth: double.infinity,
                          height: 50,
                          onPressed: () {
                            if (_formKey.currentState.validate()) {
                              Navigator.pushReplacement(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) => HomePage()));
                            }
                            //checkAndSave();
                          },
                          color: ColorUtils.appColor,
                          elevation: 0,
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(10)),
                          child: Text(
                            "Sign in",
                            style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 18,
                                color: Colors.white),
                          ),
                        ),
                      )),
                  FadeAnimation(
                      1.6,
                      InkWell(
                          onTap: () {
                            Navigator.pushReplacement(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => SignupPage()));
                          },
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              Text("Don't have an account?"),
                              Text(
                                "Sign up",
                                style: TextStyle(
                                    fontWeight: FontWeight.w600, fontSize: 18),
                              ),
                            ],
                          ))),
                ],
              ),
            ]),
          ),
        ),
      ),
You can Download Source Code via Github.