Beautiful Android Login Screen Design Tutorial

Last modified on March 4th, 2015 by Joe.

Aesthetics is critical in mobile world. Beautiful functional design is key to success of a mobile application. In this Android tutorial, let us work on designing a clean and lovable login screen for an Android app. This is a repeated task and every Android developer will come have across this, if not sooner.

In this tutorial we will focus on design as well as the backend functionality. When the user enters the username/email and password, we will validate the user input, then cross check with the credentials store and decide on authentication success or failure. The example app accompanying this tutorial can be used by you as a component for your Android mobile application. Its free for you.

Login Screen Activity Design

The Android mobile viewport is logically divided into three parts.

  1. Upper part contains the LOGO.
  2. Middle part contains the input elements.
  3. Bottom part contains the link for “Signup” activity.

When the layout is coded, care should be taken to obtain the above in a generic way. Should I say in a responsive way. The point is, the UI should not break for different mobile device sizes. These three component should be evenly spaced in any device.

Android-Login-Screen-Design

I have chosen a bright background color. Its lilac flavored color tone. Its applied to the root layout element and you can change as per your liking. Remember, Login button has the darkest hue of the background color. All the other elements are in white color. This design follows the latest trend and a safest design principle. I have used the “Roboto Light” font for the text. It looks sleek and neat.

Download

Login Android Activity

activity_login.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal"
    android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" tools:context=".LoginActivity"
    android:background="#ffBE80FF"
    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true">

    <LinearLayout
        android:id="@+id/ll1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center_vertical|center_horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="FOOBAR"
            android:id="@+id/textView2"
            android:textSize="30dp"
            android:textColor="#ffffffff" />


    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center_vertical|center_horizontal">
        <ProgressBar android:id="@+id/login_progress" style="?android:attr/progressBarStyleLarge"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:visibility="gone" />
        <ScrollView android:id="@+id/login_form" android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
                android:orientation="vertical">

                <LinearLayout android:id="@+id/email_login_form" android:layout_width="match_parent"
                    android:layout_height="wrap_content" android:orientation="vertical">

                    <AutoCompleteTextView android:id="@+id/email" android:layout_width="match_parent"
                        android:layout_height="wrap_content" android:hint="@string/prompt_email"
                        android:inputType="textEmailAddress" android:maxLines="1"
                        android:singleLine="true"
                        android:layout_marginBottom="10dp"
                        android:textColorHint="#ffffffff"
                        android:textColor="#ffffffff" />

                    <EditText android:id="@+id/password" android:layout_width="match_parent"
                        android:layout_height="wrap_content" android:hint="@string/prompt_password"
                        android:imeActionLabel="@string/action_sign_in"
                        android:imeOptions="actionUnspecified" android:inputType="textPassword"
                        android:maxLines="1" android:singleLine="true"
                        android:layout_marginBottom="10dp"
                        android:textColorHint="#ffffffff"
                        android:textColor="#ffffffff" />

                    <Button android:id="@+id/email_sign_in_button" style="?android:textAppearanceSmall"
                        android:layout_width="match_parent" android:layout_height="wrap_content"
                        android:layout_marginTop="16dp" android:text="@string/action_sign_in"
                        android:textStyle="bold"
                        android:textColor="#ffffffff"
                        android:background="#ff7e51c2" />

                </LinearLayout>
            </LinearLayout>
        </ScrollView>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="bottom|center_horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Sign up"
            android:id="@+id/signUpTextView"
            android:autoLink="web"
            android:textColor="#ffffffff" />
    </LinearLayout>
</LinearLayout>

styles.xml

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorControlNormal">#ffffff</item>
        <item name="colorControlActivated">@color/accent</item>
        <item name="colorControlHighlight">@color/accent</item>
        <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
        <item name="android:autoCompleteTextViewStyle">@style/RobotoAutoCompleteTextViewStyle</item>
        <item name="android:editTextStyle">@style/RobotoEditTextStyle</item>
    </style>
    <style name="RobotoTextViewStyle" parent="android:Widget.TextView">
        <item name="android:fontFamily">sans-serif-light</item>
    </style>
    <style name="RobotoAutoCompleteTextViewStyle" parent="android:Widget.AutoCompleteTextView">
        <item name="android:fontFamily">sans-serif-light</item>
    </style>
    <style name="RobotoEditTextStyle" parent="android:Widget.EditText">
        <item name="android:fontFamily">sans-serif-light</item>
    </style>
    <color name="accent">#ffffff</color>
</resources>

string_activity_login.xml

<resources>
    <!-- Strings related to login -->
    <string name="prompt_email">Email</string>
    <string name="prompt_password">Password</string>
    <string name="action_sign_in">Login</string>
    <string name="invalid_email">This email address is invalid</string>
    <string name="invalid_password">Password is too short</string>
    <string name="incorrect_password">Password is incorrect</string>
    <string name="field_required">This field is required</string>
</resources>

Android Login Activity Class

This is one long class, which contains everything for Login functionality. The core functions it performs are,

  1. Once the user submitted the login button, a progress spinner is shown.
  2. Auto complete for email input.
  3. Validating the User input.
  4. Authenticate the input using an AsyncTask.
  5. On success forward to a main Activity.
  6. On failure show error message on Login screen.
  7. On click of “Sign up” forward user to SignupActivity.

LoginActivity.java

package com.javapapers.android.androidloginscreen;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.graphics.Paint;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;


/**
 * Android login screen Activity
 */
public class LoginActivity extends Activity implements LoaderCallbacks<Cursor> {

    private static final String DUMMY_CREDENTIALS = "user@test.com:hello";

    private UserLoginTask userLoginTask = null;
    private View loginFormView;
    private View progressView;
    private AutoCompleteTextView emailTextView;
    private EditText passwordTextView;
    private TextView signUpTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        emailTextView = (AutoCompleteTextView) findViewById(R.id.email);
        loadAutoComplete();

        passwordTextView = (EditText) findViewById(R.id.password);
        passwordTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == EditorInfo.IME_NULL) {
                    initLogin();
                    return true;
                }
                return false;
            }
        });

        Button loginButton = (Button) findViewById(R.id.email_sign_in_button);
        loginButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                initLogin();
            }
        });

        loginFormView = findViewById(R.id.login_form);
        progressView = findViewById(R.id.login_progress);

        //adding underline and link to signup textview
        signUpTextView = (TextView) findViewById(R.id.signUpTextView);
        signUpTextView.setPaintFlags(signUpTextView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        Linkify.addLinks(signUpTextView, Linkify.ALL);

        signUpTextView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("LoginActivity", "Sign Up Activity activated.");
                // this is where you should start the signup Activity
                // LoginActivity.this.startActivity(new Intent(LoginActivity.this, SignupActivity.class));
            }
        });
    }

    private void loadAutoComplete() {
        getLoaderManager().initLoader(0, null, this);
    }


    /**
     * Validate Login form and authenticate.
     */
    public void initLogin() {
        if (userLoginTask != null) {
            return;
        }

        emailTextView.setError(null);
        passwordTextView.setError(null);

        String email = emailTextView.getText().toString();
        String password = passwordTextView.getText().toString();

        boolean cancelLogin = false;
        View focusView = null;

        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
            passwordTextView.setError(getString(R.string.invalid_password));
            focusView = passwordTextView;
            cancelLogin = true;
        }

        if (TextUtils.isEmpty(email)) {
            emailTextView.setError(getString(R.string.field_required));
            focusView = emailTextView;
            cancelLogin = true;
        } else if (!isEmailValid(email)) {
            emailTextView.setError(getString(R.string.invalid_email));
            focusView = emailTextView;
            cancelLogin = true;
        }

        if (cancelLogin) {
            // error in login
            focusView.requestFocus();
        } else {
            // show progress spinner, and start background task to login
            showProgress(true);
            userLoginTask = new UserLoginTask(email, password);
            userLoginTask.execute((Void) null);
        }
    }

    private boolean isEmailValid(String email) {
        //add your own logic
        return email.contains("@");
    }

    private boolean isPasswordValid(String password) {
        //add your own logic
        return password.length() > 4;
    }

    /**
     * Shows the progress UI and hides the login form.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    public void showProgress(final boolean show) {
        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
        // for very easy animations. If available, use these APIs to fade-in
        // the progress spinner.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

            loginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
            loginFormView.animate().setDuration(shortAnimTime).alpha(
                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    loginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
                }
            });

            progressView.setVisibility(show ? View.VISIBLE : View.GONE);
            progressView.animate().setDuration(shortAnimTime).alpha(
                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    progressView.setVisibility(show ? View.VISIBLE : View.GONE);
                }
            });
        } else {
            // The ViewPropertyAnimator APIs are not available, so simply show
            // and hide the relevant UI components.
            progressView.setVisibility(show ? View.VISIBLE : View.GONE);
            loginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        }
    }


    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        return new CursorLoader(this,
                // Retrieve data rows for the device user's 'profile' contact.
                Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
                        ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,

                // Select only email addresses.
                ContactsContract.Contacts.Data.MIMETYPE +
                        " = ?", new String[]{ContactsContract.CommonDataKinds.Email
                .CONTENT_ITEM_TYPE},

                // Show primary email addresses first. Note that there won't be
                // a primary email address if the user hasn't specified one.
                ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        List<String> emails = new ArrayList<String>();
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            emails.add(cursor.getString(ProfileQuery.ADDRESS));
            cursor.moveToNext();
        }

        addEmailsToAutoComplete(emails);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {

    }

    private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
        //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
        ArrayAdapter<String> adapter =
                new ArrayAdapter<String>(LoginActivity.this,
                        android.R.layout.simple_dropdown_item_1line, emailAddressCollection);

        emailTextView.setAdapter(adapter);
    }


    private interface ProfileQuery {
        String[] PROJECTION = {
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
        };

        int ADDRESS = 0;
        int IS_PRIMARY = 1;
    }

    /**
     * Async Login Task to authenticate
     */
    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {

        private final String emailStr;
        private final String passwordStr;

        UserLoginTask(String email, String password) {
            emailStr = email;
            passwordStr = password;
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            //this is where you should write your authentication code
            // or call external service
            // following try-catch just simulates network access
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                return false;
            }

            //using a local dummy credentials store to authenticate
            String[] pieces = DUMMY_CREDENTIALS.split(":");
            if (pieces[0].equals(emailStr) && pieces[1].equals(passwordStr)) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            userLoginTask = null;
            //stop the progress spinner
            showProgress(false);

            if (success) {
                //  login success and move to main Activity here.
            } else {
                // login failure
                passwordTextView.setError(getString(R.string.incorrect_password));
                passwordTextView.requestFocus();
            }
        }

        @Override
        protected void onCancelled() {
            userLoginTask = null;
            showProgress(false);
        }
    }
}

Download

Comments on "Beautiful Android Login Screen Design Tutorial"

  1. Firoz says:

    Nice Idea,This Time…

  2. sathish says:

    super

  3. Pratik says:

    Thanks Joe :)

  4. wilson says:

    simply awesome..!!

  5. Dinesh Balayan says:

    awesome code to learn something new for me i m new in android
    thanks

  6. deepa says:

    Thanks,Great work.

  7. elmahbub says:

    aweasome

  8. allea says:

    i am getting an error in the styles.xml file on the itemname color control normal,can someone plese help me to resolve it??

  9. genfior says:

    please i want to use this code in my project how do i use sheredpreference

  10. kavya says:

    its awesome……it helped me lot…ty

Comments are closed for "Beautiful Android Login Screen Design Tutorial".