每一個人都會喜歡漂亮的登陸界面,一個App 給人們的第一印象是很是重要的。html
這篇文章將教你使用谷歌材料設計規範(Material design spec )和谷歌的新的設計支持庫( design support library)來建立一個炫酷的登陸和註冊界面。設計支持庫實現了材料設計規範的一部分,它包含了一部分炫酷的UI 部件,讓你的Android 應用給人一種優雅的感受。java
對事物的設計和佈局方面,如何作到讓人感受到屏幕上的內容是賞心悅目的,這裏是咱們要權衡的重點,咱們會在頂部狀態欄添加精細的觸摸事件,並使用設計支持庫的floating labels (實現自TextInputLayout)。android
幾乎全部的事情都都已經照顧到你。git
完整的代碼和樣例託管在Githubgithub
當接口鎖定時,防止後退按鈕顯示在登陸Activity 上。微信
自定義 ProgressDialog
來顯示加載的狀態。app
符合材料設計規範。ide
懸浮標籤(floating labels)(來自設計支持庫)佈局
用戶表單輸入校驗post
自定義狀態欄樣式
在每個Activity 測試模仿驗證的方法。
剩下的就是實現本身的身份驗證邏輯。
讓咱們來設置登陸Activity,一般是開始你的應用程序,會顯示給用戶的第一個要啓動的Activity。
若是你想要添加社交登陸按鈕,請繼續,可是當前在這個文章範圍內,只給你基本的代碼,讓你有一個堅固的起點去構建你的驗證流程。
須要注意的是 onBackPressed
方法將會被重寫,這樣將會防止用戶關閉登陸Activity。
package com.sourcey.materiallogindemo; import android.app.ProgressDialog; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.content.Intent; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import butterknife.ButterKnife; import butterknife.InjectView; public class LoginActivity extends AppCompatActivity { private static final String TAG = "LoginActivity"; private static final int REQUEST_SIGNUP = 0; @Bind(R.id.input_email) EditText _emailText; @Bind(R.id.input_password) EditText _passwordText; @Bind(R.id.btn_login) Button _loginButton; @Bind(R.id.link_signup) TextView _signupLink; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ButterKnife.inject(this); _loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { login(); } }); _signupLink.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Start the Signup activity Intent intent = new Intent(getApplicationContext(), SignupActivity.class); startActivityForResult(intent, REQUEST_SIGNUP); } }); } public void login() { Log.d(TAG, "Login"); if (!validate()) { onLoginFailed(); return; } _loginButton.setEnabled(false); final ProgressDialog progressDialog = new ProgressDialog(LoginActivity.this, R.style.AppTheme_Dark_Dialog); progressDialog.setIndeterminate(true); progressDialog.setMessage("Authenticating..."); progressDialog.show(); String email = _emailText.getText().toString(); String password = _passwordText.getText().toString(); // TODO: Implement your own authentication logic here. new android.os.Handler().postDelayed( new Runnable() { public void run() { // On complete call either onLoginSuccess or onLoginFailed onLoginSuccess(); // onLoginFailed(); progressDialog.dismiss(); } }, 3000); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_SIGNUP) { if (resultCode == RESULT_OK) { // TODO: Implement successful signup logic here // By default we just finish the Activity and log them in automatically this.finish(); } } } @Override public void onBackPressed() { // disable going back to the MainActivity moveTaskToBack(true); } public void onLoginSuccess() { _loginButton.setEnabled(true); finish(); } public void onLoginFailed() { Toast.makeText(getBaseContext(), "Login failed", Toast.LENGTH_LONG).show(); _loginButton.setEnabled(true); } public boolean validate() { boolean valid = true; String email = _emailText.getText().toString(); String password = _passwordText.getText().toString(); if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) { _emailText.setError("enter a valid email address"); valid = false; } else { _emailText.setError(null); } if (password.isEmpty() || password.length() < 4 || password.length() > 10) { _passwordText.setError("between 4 and 10 alphanumeric characters"); valid = false; } else { _passwordText.setError(null); } return valid; } }
<img src="http://sourcey.com/beautiful-android-logn-and-signup-screens-with-material-design/screenshot-login.png" width="360" height="640" />
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fitsSystemWindows="true"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="56dp" android:paddingLeft="24dp" android:paddingRight="24dp"> <ImageView android:src="@drawable/logo" android:layout_width="wrap_content" android:layout_height="72dp" android:layout_marginBottom="24dp" android:layout_gravity="center_horizontal" /> <!-- Email Label --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" android:hint="Email" /> </android.support.design.widget.TextInputLayout> <!-- Password Label --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="Password"/> </android.support.design.widget.TextInputLayout> <android.support.v7.widget.AppCompatButton android:id="@+id/btn_login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" android:padding="12dp" android:text="Login"/> <TextView android:id="@+id/link_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:text="No account yet? Create one" android:gravity="center" android:textSize="16dip"/> </LinearLayout> </ScrollView>
註冊Activity 可讓你在App 中建立一個用戶,一般會在登陸Activity 中顯示(註冊的)連接。
<img src="http://sourcey.com/beautiful-android-logn-and-signup-screens-with-material-design/screenshot-signup.png" width="360" height="640" />
須要注意的是當用戶註冊成功時咱們會設置一個RESULT_OK
的結果值,這個結果將會在登陸Activity 中的 onActivityResult
方法中調用,而且肯定註冊成功是如何處理的。當前邏輯是很簡單的,當用戶註冊成功時咱們會立刻作一個記錄。固然你想要實現郵箱驗證,你須要本身來實現。
package com.sourcey.materiallogindemo; import android.app.ProgressDialog; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import butterknife.ButterKnife; import butterknife.InjectView; public class SignupActivity extends AppCompatActivity { private static final String TAG = "SignupActivity"; @Bind(R.id.input_name) EditText _nameText; @Bind(R.id.input_email) EditText _emailText; @Bind(R.id.input_password) EditText _passwordText; @Bind(R.id.btn_signup) Button _signupButton; @Bind(R.id.link_login) TextView _loginLink; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_signup); ButterKnife.inject(this); _signupButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { signup(); } }); _loginLink.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Finish the registration screen and return to the Login activity finish(); } }); } public void signup() { Log.d(TAG, "Signup"); if (!validate()) { onSignupFailed(); return; } _signupButton.setEnabled(false); final ProgressDialog progressDialog = new ProgressDialog(SignupActivity.this, R.style.AppTheme_Dark_Dialog); progressDialog.setIndeterminate(true); progressDialog.setMessage("Creating Account..."); progressDialog.show(); String name = _nameText.getText().toString(); String email = _emailText.getText().toString(); String password = _passwordText.getText().toString(); // TODO: Implement your own signup logic here. new android.os.Handler().postDelayed( new Runnable() { public void run() { // On complete call either onSignupSuccess or onSignupFailed // depending on success onSignupSuccess(); // onSignupFailed(); progressDialog.dismiss(); } }, 3000); } public void onSignupSuccess() { _signupButton.setEnabled(true); setResult(RESULT_OK, null); finish(); } public void onSignupFailed() { Toast.makeText(getBaseContext(), "Login failed", Toast.LENGTH_LONG).show(); _signupButton.setEnabled(true); } public boolean validate() { boolean valid = true; String name = _nameText.getText().toString(); String email = _emailText.getText().toString(); String password = _passwordText.getText().toString(); if (name.isEmpty() || name.length() < 3) { _nameText.setError("at least 3 characters"); valid = false; } else { _nameText.setError(null); } if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) { _emailText.setError("enter a valid email address"); valid = false; } else { _emailText.setError(null); } if (password.isEmpty() || password.length() < 4 || password.length() > 10) { _passwordText.setError("between 4 and 10 alphanumeric characters"); valid = false; } else { _passwordText.setError(null); } return valid; } }
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fitsSystemWindows="true"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="56dp" android:paddingLeft="24dp" android:paddingRight="24dp"> <ImageView android:src="@drawable/logo" android:layout_width="wrap_content" android:layout_height="72dp" android:layout_marginBottom="24dp" android:layout_gravity="center_horizontal" /> <!-- Name Label --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textCapWords" android:hint="Name" /> </android.support.design.widget.TextInputLayout> <!-- Email Label --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" android:hint="Email" /> </android.support.design.widget.TextInputLayout> <!-- Password Label --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="Password"/> </android.support.design.widget.TextInputLayout> <!-- Signup Button --> <android.support.v7.widget.AppCompatButton android:id="@+id/btn_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" android:padding="12dp" android:text="Create Account"/> <TextView android:id="@+id/link_login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:text="Already a member? Login" android:gravity="center" android:textSize="16dip"/> </LinearLayout> </ScrollView>
爲了讓程序一切正常工做,咱們在須要在 app
目錄下的 build.gradle
中添加一些依賴,ButterKnife
是可選的,固然咱們更喜歡用它讓咱們的Java 代碼更加整潔一些。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.0' compile 'com.jakewharton:butterknife:7.0.1' }
還有一個咱們必需要在AndroidManifest
中添加聲明Activity。我已經把AndroidManifest
清晰完整的代碼貼了出來。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sourcey.materiallogindemo" > <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".LoginActivity" android:theme="@style/AppTheme.Dark" /> <activity android:name=".SignupActivity" android:theme="@style/AppTheme.Dark" /> </application> </manifest>
但願這篇文章對你是有幫助的,若是這篇文章真的節約你寶貴的開發時間,請給我留言。
本文做者:sourcey
本文譯者:Tikitoo
原文連接:http://sourcey.com/beautiful-android-login-and-signup-screens-with-material-design/
翻譯連接:http://tikitoo.github.io/2016/05/17/beautiful-android-login-and-signup-screens-with-material-design-zh/
非商業轉載轉載請在開頭註明做者詳細信息
和本文出處
,以及本文全部內容。本文首發個人微信公衆號,分享
Android 開發
和互聯網內容
。
微信號:AndroidMate
公衆號:安卓同窗