文章目录[隐藏]
每个人都会喜欢漂亮的登录界面,一个App 给人们的第一印象是非常重要的。
每个人都会喜欢漂亮的登录界面,一个App 给人们的第一印象是非常重要的。
这篇文章将教你使用谷歌材料设计规范(Material design spec )和谷歌的新的设计支持库( design support library)来创建一个炫酷的登录和注册界面。设计支持库实现了材料设计规范的一部分,它包含了一部分炫酷的UI 部件,让你的Android 应用给人一种优雅的感觉。
对事物的设计和布局方面,如何做到让人感觉到屏幕上的内容是赏心悦目的,这里是我们要权衡的重点,我们会在顶部状态栏添加精细的触摸事件,并使用设计支持库的floating labels (实现自TextInputLayout)。
几乎所有的事情都都已经照顾到你。
- 完整的代码和样例托管在Github
- 当接口锁定时,防止后退按钮显示在登录Activity 上。
- 自定义 ProgressDialog
来显示加载的状态。
- 符合材料设计规范。
- 悬浮标签(floating labels)(来自设计支持库)
- 用户表单输入校验
- 自定义状态栏样式
- 在每一个Activity 测试模仿验证的方法。
剩下的就是实现自己的身份验证逻辑。
登录Activity
让我们来设置登录Activity,通常是开始你的应用程序,会显示给用户的第一个要启动的Activity。
如果你想要添加社交登录按钮,请继续,但是当前在这个文章范围内,只给你基本的代码,让你有一个坚固的起点去构建你的验证流程。
需要注意的是 onBackPressed
方法将会被重写,这样将会防止用户关闭登录Activity。
LoginActivity.java 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; } }
res/layout/activity_login.xml
<?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
注册Activity 可以让你在App 中创建一个用户,通常会在登录Activity 中显示(注册的)链接。
需要注意的是当用户注册成功时我们会设置一个RESULT_OK
的结果值,这个结果将会在登录Activity 中的 onActivityResult
方法中调用,并且确定注册成功是如何处理的。当前逻辑是很简单的,当用户注册成功时我们会马上做一个记录。当然你想要实现邮箱验证,你需要自己来实现。
SignupActivity.java
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; } }
res/layout/activity_signup.xml
<?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>
希望这篇文章对你是有帮助的,如果这篇文章真的节约你宝贵的开发时间,请给我留言。