Learn to design a beautiful Login/Signup (registration flow) in Flutter

 Introduction:

In this post, we are going to learn how to build a beautiful login/signup (registration flow)for your app. We are going to build it from scratch and understand various widgets that you can use to build an elegant screen. You might have already seen some beautiful screens been designed using flutter. Flutter gives you the flexibility to design your own custom widgets and import them to build sleek designs.

Demo

The final result of the app



Prerequisites

This tutorial assumes a little knowledge of Flutter or Dart. JavaScript knowledge will be helpful as well, especially ES6 features. You should have:

Visual Studio Code editor / Android studio installed on your machine if you haven’t yet. We’ll use it in our tutorial.


Project setup

Simply create a new project in flutter and give it the name flutter_login_app.


Directory structure

Once the project is created, open it into Android Studio. We’re using Android studio because it has the most complete Flutter support (Dart syntax, code completion, debugging tools). By default, you should see the following directory structure:

  1. android - where Android-related files are stored. If you’ve done any sort of cross-platform mobile app development before, this, along with the ios folder should be pretty familiar.
  2. ios - where iOS-related files are stored.
  3. lib - This is where you’ll be working most of the time. By default, it contains a main. dart file, this is the entry point file of the Flutter app. we are going to create our own widget for login/signup here.
  4. test - this is where you put the unit testing code for the app. We won’t really be working on it in this tutorial.
  5. pubspec.yaml - this file defines the version and build number of your app. It’s also where you define your dependencies. If you’re coming from a web development background, this file has the same job description as the package.json file so you can define the external packages (from the Dart packages website) you want to use in here.

Note that I’ve skipped on other folders and files because most of the time you won’t really need to touch them.


First, we will start by creating a new widget file which we will use in the later stages.

Create two dart named login.dart and signup.dart files under the lib folder as seen in the below pics.


Build the UI.

Let start by looking into the main.dart file

Create a new stateless widget class called HomePage.

  • Stateful widget: manages its own internal state and keeps track of it.
  • Stateless widget: while this kind of widget doesn’t. For example, a button doesn’t need to track anything.

We want to have a title with some text, then we have an image or illustration below that we have two buttons more specific Material button widget for login and signup.

To have the flexibility we are going to use the SafeArea widget along with Media queries. Add the below code to get the initial text Hello There!




body: SafeArea(
        child: Container(
          width: double.infinity,
          height: MediaQuery.of(context).size.height,
          padding: EdgeInsets.symmetric(horizontal: 30,vertical: 30),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    "Hello There!",
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 40),
                  ),
                  SizedBox(height: 30,),
                  Text("Automatic identity verification which enable you to verify your identity",
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: Colors.grey[700],
                        fontSize: 15
                      ),
                  ),
                ],
              ),
Next, we are going to add an illustration to our home page ,First, we need to add the assets to pubspec.yaml file Make sure to follow the YAML structure.

assets:
    - assets/Illustration.png 
    
 
We are going to add the illustration inside a container with a height of 1/3 of the screen size inside a media query.

Container(
                height: MediaQuery.of(context).size.height/3,
                decoration: BoxDecoration(
                  image:DecorationImage(image: AssetImage('assets/Illustration.png'))
                ),
              ),
              
  
Next to add two buttons for login/signup. We are going to use the MaterialButton widget with an onpressed() event which we will cover later on how to have the click functionality for a button. To add a material button you can use the below code for the login and signup button: 

Login Button

MaterialButton(
                    minWidth: double.infinity,
                    height:60,
                    onPressed: (){
                      
                    },
                    color: Colors.indigoAccent[400],
                    shape: RoundedRectangleBorder(
                      side: BorderSide(
                        color: Colors.black,
                      ),
                      borderRadius: BorderRadius.circular(40)
                    ),
                    child: Text("Login",style: TextStyle(
                      fontWeight: FontWeight.w600,fontSize: 16,color: Colors.white70

                    ),),

 
Sign up Button

MaterialButton(
                      minWidth: double.infinity,
                      height:60,
                      onPressed: (){
                        
                      },
                      color: Colors.redAccent,
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(40)
                      ),
                      child: Text("Sign UP",style: TextStyle(
                        fontWeight: FontWeight.w600,fontSize: 16,

                      ),),
                    ),	
   


Designing the Login/Sign Up page We are going to design our login and signup page to do that we need to edit our already created login.dart and signup.dart file

Add the below code for login.dart file



import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
        backgroundColor: Colors.white,
        appBar: AppBar(
          elevation: 0,
          brightness: Brightness.light,
          backgroundColor: Colors.white,
          leading:
          IconButton( onPressed: (){
            Navigator.pop(context);
          },icon:Icon(Icons.arrow_back_ios,size: 20,color: Colors.black,)),
        ),
      body: Container(
        height: MediaQuery.of(context).size.height,
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Column(
              children: [
                Column(
                  children: [
                    Text ("Login", style: TextStyle(
                      fontSize: 30,
                      fontWeight: FontWeight.bold,
                    ),),
                    SizedBox(height: 20,),
                    Text("Welcome back ! Login with your credentials",style: TextStyle(
                      fontSize: 15,
                      color: Colors.grey[700],
                    ),),
                    SizedBox(height: 30,)
                  ],
                ),
                Padding(
                  padding: EdgeInsets.symmetric(
                    horizontal: 40
                  ),
                  child: Column(
                    children: [
                      makeInput(label: "Email"),
                      makeInput(label: "Password",obsureText: true),
                    ],
                  ),
                ),
                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 40),
                  child: Container(
                    padding: EdgeInsets.only(top: 3,left: 3),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(40),
                        border: Border(
                            bottom: BorderSide(color: Colors.black),
                            top: BorderSide(color: Colors.black),
                            right: BorderSide(color: Colors.black),
                            left: BorderSide(color: Colors.black)
                        )
                    ),
                    child: MaterialButton(
                      minWidth: double.infinity,
                      height:60,
                      onPressed: (){},
                      color: Colors.indigoAccent[400],
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(40)
                      ),
                      child: Text("Login",style: TextStyle(
                        fontWeight: FontWeight.w600,fontSize: 16,color: Colors.white70
                      ),),
                    ),
                  ),
                ),
                SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text("Dont have an account?"),
                    Text("Sign Up",style: TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 18
                    ),),
                  ],
                )
              ],

            ),
          ],
        ),
      ),
    );
  }
}

Widget makeInput({label,obsureText = false}){
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(label,style:TextStyle(
        fontSize: 15,
        fontWeight: FontWeight.w400,
        color: Colors.black87
      ),),
      SizedBox(height: 5,),
      TextField(
        obscureText: obsureText,
        decoration: InputDecoration(
          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: 30,)

    ],
  );
}


Add the below code to signup.dart file

import 'package:flutter/material.dart';

class SignupPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      resizeToAvoidBottomPadding: false,
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 0,
        brightness: Brightness.light,
        backgroundColor: Colors.white,
        leading:
        IconButton( onPressed: (){
          Navigator.pop(context);
        },icon:Icon(Icons.arrow_back_ios,size: 20,color: Colors.black,)),
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          child: Container(
            height: MediaQuery.of(context).size.height,
            width: double.infinity,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Column(
                  children: [
                    Column(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        Text ("Sign up", style: TextStyle(
                          fontSize: 30,
                          fontWeight: FontWeight.bold,
                        ),),
                        SizedBox(height: 20,),
                        Text("Create an Account,Its free",style: TextStyle(
                          fontSize: 15,
                          color: Colors.grey[700],
                        ),),
                        SizedBox(height: 30,)
                      ],
                    ),
                    Padding(
                      padding: EdgeInsets.symmetric(
                          horizontal: 40
                      ),
                      child: Column(
                        children: [
                          makeInput(label: "Email"),
                          makeInput(label: "Password",obsureText: true),
                          makeInput(label: "Confirm Pasword",obsureText: true)
                        ],
                      ),
                    ),
                    Padding(
                      padding: EdgeInsets.symmetric(horizontal: 40),
                      child: Container(
                        padding: EdgeInsets.only(top: 3,left: 3),
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(40),
                            border: Border(
                                bottom: BorderSide(color: Colors.black),
                                top: BorderSide(color: Colors.black),
                                right: BorderSide(color: Colors.black),
                                left: BorderSide(color: Colors.black)
                            )
                        ),
                        child: MaterialButton(
                          minWidth: double.infinity,
                          height:60,
                          onPressed: (){},
                          color: Colors.redAccent,
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(40)
                          ),
                          child: Text("Sign Up",style: TextStyle(
                            fontWeight: FontWeight.w600,fontSize: 16,

                          ),),
                        ),
                      ),
                    ),
                    SizedBox(height: 20,),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text("Already have an account? "),
                        Text("Login",style: TextStyle(
                            fontWeight: FontWeight.w600,
                            fontSize: 18
                        ),),
                      ],
                    )
                  ],

                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Widget makeInput({label,obsureText = false}){
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(label,style:TextStyle(
          fontSize: 15,
          fontWeight: FontWeight.w400,
          color: Colors.black87
      ),),
      SizedBox(height: 5,),
      TextField(
        obscureText: obsureText,
        decoration: InputDecoration(
          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: 30,)

    ],
  );
}

Conclusion:
This is a very simple Flutter Application, demonstrating the Login or Sign-in screen.  Most of the widgets used like Text and FlatButton are surrounded in Container widgets. You may change the colors, padding, margin or backgrounds, to suit the theme of your application. In the next tutorial we are going to develop api using node.js to test the application.

Cheers!
Happy Coding 😀

Hey I'm Venkat
Developer, Blogger, Thinker and Data scientist. nintyzeros [at] gmail.com I love the Data and Problem - An Indian Lives in US .If you have any question do reach me out via below social media