Simple & Clean Login UI Using Flutter

Mais Alheraki
The Startup
Published in
5 min readJul 8, 2019

My story with Flutter has begun 6 months ago, and today I finally decided to start sharing my tiny fingerprint in the Flutter community.
I will be explaining the different parts of a Login UI flutter code, but first, let me show you how it will look like! let’s go!

Photo by Ben Kolde on Unsplash

Initial Design

First things first, I started by making a UI design on Sketch, following my only and forever design concept “Keep it simple!”.

The UI design using Sketch

Note: to be able to follow up with this article, I’m expecting you to have minimum expertise with Flutter.

Code

Let’s now dive into the code!
Of course, we start from main.dart, declaring the main method and some theming rules.

Note that we will set the DeviceOrientation to Portrait Up, cause we don’t want to deal with the mess that happens if the device orientation changed.

Pretty simple.

Now let’s take a look at MyApp class, I declared some theming rules here.

Next and main step, the home.dart which contains most of our code. First, we write Home StatefulWidget class and declare all necessary variables to store the user input later.

The real work starts here, inside the build method, but first let me split up our UI to understand how we are going to code it.

We have 3 pages:

  1. The main page which contains a logo, and 2 buttons one for login and one for register, and some curve painted in the bottom.
  2. The login page, which appears after clicking on Login button from the main page, it has 4 components: closing icon, 2 input fields and a submit button.
  3. The register page, which is a copy of the login page with 1 additional field.

Now we can start coding each component!

First, we have a Scaffold, with a key and backgroundColor, we will set the resizeToAvoidBottomPadding to false cause it will make some mess later with the input fields when the keyboard gets over them.

Inside the Column widget, we will add the logo() widget, to draw that nice simple logo using Stack and Positioned widgets. Logo() will be outside the build method, to make our code cleaner.

It’s buttons’ turn. We have 2 buttons, one RaisedButton, and the other is an OutlineButton. Why did we use 2 different kinds of widgets for each button?
Simply for the sake of styling :D
RaisedButton makes it easy to give it a fill color, which is what we wanted for the login button (with a white fill). OutlineButton makes it easier to have a button with a border but with no fill, which is what we wanted for register button.
I’m really bad at arranging my codes… so this is the best idea that came up to my mind. I used the raised button many times across the code, but outline button only one, so I thought it will be better to make one raised button as a function and give it the following parameters to make it reusable:

Widget _button (String text, Color splashColor, Color highlightColor, Color fillColor, Color textColor, void function()){}

Such a long list of parameters! but much better than writing same button code many times!

So here is the full code for our RaisedButton widget:

And here is the OutlineButton:

Last part of the main page is this curved white shape in the bottom, wondering how to do it? we will use ClipPath widget.
Inside the Column in the body of our Scaffold, we will add this code to draw the curved shape:

Let’s move to a new file called clipper.dart, which will contain the class BottomWaveClipper that will draw the curved path.

So magical! we are done with the main page, let’s move forward.

It looks like login and register pages are new routes in the app, but they aren’t, each of them are just a PersistentBottomSheet!
PersistentBottomSheet are bottom sheets that is drawn into the screen from the bottom over the main context, and we can fit whatever we want inside them.

Let’s add the following functions to onPressed property on each of the buttons (actually we will pass the first one to the _button function without the brackets):

_loginSheet
_registerSheet()

Did you guess what are they? yup, exactly! they functions that will return the login and register sheets. The code for each one is long and I won’t include it all here, but we will take a look at some important features of it.

  1. It’s wrapped inside a DecoratedBox widget, and then a ClipRRect, to give it top corners radius.
  2. The elements are wrapped with a ListView instead of a Column, for scrolling sake, when the keyboard goes above the password field and submit button, giving the user the ability to scroll will solve the problem.
DecoratedBox(
decoration: BoxDecoration(color: Theme.of(context).canvasColor),
child: ClipRRect(borderRadius: BorderRadius.only(
topLeft: Radius.circular(40.0),
topRight: Radius.circular(40.0)),
child: Container( child: ListView())
)
)

Same goes for both sheets, login, and register.

Now is InputField’s turn, which will be a function called _input that will return the desired InputField widget:

So each time we want to use an input field, we just have to call this function and provide it with the arguments that fit our use. We have 5 input fields, that will be drawn from this function, pretty neat and elegant.

We are done!

You can Find the source code on GitHub here. 💙
Reach me out on Twitter @pr_Mais, and LinkedIn ! Thank you for reading!

--

--

Mais Alheraki
The Startup

Software engineer, Geek, Designer, Reader & always a Lifetime Learner!