由於項目中大部分界面都有一個后退鍵和一個標題欄,為避免代碼冗雜以及便於利用,我們可以將后推薦和標題欄單獨抽取出來定義一個標題欄布局,在 res/layout 目錄下新建一個 Layout resource file ,Root element 選用 RelativeLayout
具體代碼如下:
main_title_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/transparent">
<TextView
android:id="@+id/tv_back"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:background="@drawable/go_back_selector" />
<TextView
android:id="@+id/tv_main_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="20sp" />
</RelativeLayout>
注冊界面
思路
將圖片導入 drawable 目錄下,在 activity 包下創建 RegisterActivity ,修改 activity_register.xml 為 LinearLayout 布局
具體代碼如下:
activity_register.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_register"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/register_bg"
android:orientation="vertical"
tools:context="cn.edu.lt.android.boxueguapp.activity.RegisterActivity">
<include layout="@layout/main_title_bar"></include><!--引入標題欄-->
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="25dp"
android:src="@drawable/default_icon" />
<EditText
android:id="@+id/et_username"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginTop="35dp"
android:background="@drawable/register_user_name_bg"
android:drawableLeft="@drawable/user_name_icon"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:hint="請輸入用戶名"
android:paddingLeft="8dp"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<EditText
android:id="@+id/et_pwd"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/register_psw_bg"
android:drawableLeft="@drawable/psw_icon"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:hint="請輸入密碼"
android:inputType="textPassword"
android:paddingLeft="8dp"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<EditText
android:id="@+id/et_pwd_again"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/register_psw_again_bg"
android:drawableLeft="@drawable/psw_icon"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:hint="請再次輸入密碼"
android:inputType="textPassword"
android:paddingLeft="8dp"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<Button
android:id="@+id/btn_register"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginTop="15dp"
android:background="@drawable/register_selector"
android:text="注冊"
android:textColor="@android:color/white"
android:textSize="18sp" />
</LinearLayout>
MD5算法
由於注冊登錄涉及密碼,我們需要對用戶的密碼進行 MD5 算法加密,MD5 的全稱是 Message-Digest Algorithm 5(信息--摘要算法),MD5 算法簡單來說就是把任意長度的字符串變換成固定長度(通常是128位)的16進制字符串,且此算法不可逆。我們新建一個 utils 包,在此包下創建 MD5 加密工具類 MD5Utils ,具體代碼如下:
MD5Utils
package cn.edu.lt.android.boxueguapp.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by lt on 2017/12/26.
*/
public class MD5Utils {
/**
* md5加密算法
* @param text
* @return
*/
public static String md5(String text){
try {
MessageDigest digest = MessageDigest.getInstance("md5");//獲取數據指紋對象
byte[] result = digest.digest(text.getBytes());//字節數組
StringBuilder sb = new StringBuilder();//16進制轉換
for (byte b :result){//獲取所有字節進行轉換
int number = b & 0xff;//使用『與算法』,java使用unicode字符,所以每個字符占位兩個,則需要與兩位16進制最大值進行與運算,獲取number值
String hex = Integer.toHexString(number);//number值轉換字符串
if (hex.length()==1){//若轉換后的字符長度等於1則進行字符串拼接
sb.append("0" + hex);
}else {
sb.append(hex);
}
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";//發送異常return空字符串
}
}
}
注冊邏輯
思路
完成了注冊頁面的布局與 MD5 工具類后,進行注冊界面的邏輯編寫。我們在注冊界面點擊注冊按鈕后,需要獲取用戶名,用戶密碼和再次確認密碼,當兩次密碼相同時,將用戶名和密碼(經過 MD5 加密)保存到 SharedPreferences 中,同時當注冊成功之后需要將用戶名傳遞到登錄界面中。
具體代碼如下:
RegisterActivity
package cn.edu.lt.android.boxueguapp.activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import cn.edu.lt.android.boxueguapp.R;
import cn.edu.lt.android.boxueguapp.utils.MD5Utils;
public class RegisterActivity extends AppCompatActivity {
//提取全局變量:Ctrl+Alt+F
//標題
private TextView tv_main_title;
//返回按鈕
private TextView tv_back;
//注冊按鈕
private Button btn_register;
//賬號、密碼、再次輸入的密碼的控件
private EditText et_user_name,et_psw,et_psw_again;
//賬號、密碼、再次輸入的密碼的控件的獲取值
private String userName,psw,pswAgain;
//標題布局
private RelativeLayout rl_title_bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
init();
}
private void init() {
//從main_title_bar.xml頁面布局中獲取對應的UI控件
tv_main_title = (TextView) findViewById(R.id.tv_main_title);
tv_main_title.setText("注冊");
tv_back = (TextView) findViewById(R.id.tv_back);
rl_title_bar = (RelativeLayout) findViewById(R.id.title_bar);
rl_title_bar.setBackgroundColor(Color.TRANSPARENT);
//從activity_register.xml頁面布局中獲得對應的UI控件
btn_register=(Button) findViewById(R.id.btn_register);
et_user_name=(EditText) findViewById(R.id.et_username);
et_psw=(EditText) findViewById(R.id.et_pwd);
et_psw_again=(EditText) findViewById(R.id.et_pwd_again);
tv_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RegisterActivity.this.finish();
}
});
btn_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//獲取輸入在相應控件中的字符串
getEditString();
//判斷輸入框內容
if(TextUtils.isEmpty(userName)){
Toast.makeText(RegisterActivity.this, "請輸入用戶名", Toast.LENGTH_SHORT).show();
return;
}else if(TextUtils.isEmpty(psw)){
Toast.makeText(RegisterActivity.this, "請輸入密碼", Toast.LENGTH_SHORT).show();
return;
}else if(TextUtils.isEmpty(pswAgain)){
Toast.makeText(RegisterActivity.this, "請再次輸入密碼", Toast.LENGTH_SHORT).show();
return;
}else if(!psw.equals(pswAgain)){
Toast.makeText(RegisterActivity.this, "輸入兩次的密碼不一樣", Toast.LENGTH_SHORT).show();
return;
}else if(isExistUserName(userName)){
Toast.makeText(RegisterActivity.this, "此賬戶名已經存在", Toast.LENGTH_SHORT).show();
return;
}else{
Toast.makeText(RegisterActivity.this, "注冊成功", Toast.LENGTH_SHORT).show();
//把賬號、密碼和賬號標識保存到sp里面
saveRegisterInfo(userName, psw);
//注冊成功后把賬號傳遞到LoginActivity.java中
Intent data =new Intent();
data.putExtra("userName", userName);
setResult(RESULT_OK, data);
//RESULT_OK為Activity系統常量,狀態碼為-1,表示此頁面下的內容操作成功將data返回到上一頁面,如果是用back返回過去的則不存在用setResult傳遞data值
RegisterActivity.this.finish();
}
}
});
}
/**
* 獲取控件中的字符串
*/
private void getEditString(){
userName=et_user_name.getText().toString().trim();
psw=et_psw.getText().toString().trim();
pswAgain=et_psw_again.getText().toString().trim();
}
/**
*從SharedPreferences中讀取輸入的用戶名,判斷SharedPreferences中是否有此用戶名
*/
private boolean isExistUserName(String userName){
boolean has_userName=false;
SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
String spPsw=sp.getString(userName, "");//傳入用戶名獲取密碼
if(!TextUtils.isEmpty(spPsw)) {//如果密碼不為空則確實保存過這個用戶名
has_userName=true;
}
return has_userName;
}
/**
* 保存賬號和密碼到SharedPreferences中
*/
private void saveRegisterInfo(String userName,String psw){
String md5Psw= MD5Utils.md5(psw);//把密碼用MD5加密
//loginInfo表示文件名
SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
SharedPreferences.Editor editor=sp.edit();//獲取編輯器
//以用戶名為key,密碼為value保存在SharedPreferences中
editor.putString(userName, md5Psw);
editor.commit();//提交修改
}
}
登錄界面
思路
接着編寫登錄界面的布局,同理引入圖片至 drawable 目錄下,在 activity 包下創建 LoginActivity ,修改 activity_login.xml 為 LinearLayout 布局
具體代碼如下:
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<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:background="@drawable/login_bg"
tools:context="cn.edu.lt.android.boxueguapp.activity.LoginActivity"
android:orientation="vertical">
<include layout="@layout/main_title_bar"></include>
<ImageView
android:id="@+id/iv_head"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="25dp"
android:src="@drawable/default_icon" />
<EditText
android:id="@+id/et_user_name"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:layout_marginTop="35dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/login_user_name_bg"
android:drawableLeft="@drawable/user_name_icon"
android:drawablePadding="10dp"
android:paddingLeft="8dp"
android:gravity="center_vertical"
android:hint="請輸入用戶名"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<EditText
android:id="@+id/et_psw"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/login_psw_bg"
android:drawableLeft="@drawable/psw_icon"
android:drawablePadding="10dp"
android:paddingLeft="8dp"
android:hint="請輸入密碼"
android:inputType="textPassword"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<Button
android:id="@+id/btn_login"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginTop="15dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/register_selector"
android:text="登錄"
android:textColor="@android:color/white"
android:textSize="18sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="8dp"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_register"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="立即注冊"
android:textColor="@android:color/white"
android:textSize="14sp" /><!--layout_weight="1" layout_width="0dp"實現均分效果-->
<TextView
android:id="@+id/tv_find_psw"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="找回密碼?"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
登錄邏輯
思路
完成登錄界面布局后,最后我們實現登錄界面的邏輯代碼,當點擊登錄按鈕時,需先判斷用戶名和密碼是否為空,若為空則提示請輸入用戶名和密碼,若不為空則獲取用戶輸入的用戶名,由於本項目用的是本地數據,因此根據用戶名在 SharedPreferences 中查詢是否有對應的密碼,若有對應的密碼且與用戶輸入的密碼(需 MD5 加密)比對一致,則登錄成功
具體代碼如下:
LoginActivity
package cn.edu.lt.android.boxueguapp.activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import cn.edu.lt.android.boxueguapp.MainActivity;
import cn.edu.lt.android.boxueguapp.R;
import cn.edu.lt.android.boxueguapp.utils.MD5Utils;
public class LoginActivity extends AppCompatActivity {
private TextView tv_main_title;
private TextView tv_back,tv_register,tv_find_psw;
private Button btn_login;
private String userName,psw,spPsw;
private EditText et_user_name,et_psw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//設置此界面為豎屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
init();
}
/**
* 獲取界面控件
*/
private void init(){
tv_main_title=(TextView) findViewById(R.id.tv_main_title);
tv_main_title.setText("登錄");
tv_back=(TextView) findViewById(R.id.tv_back);
tv_register=(TextView) findViewById(R.id.tv_register);
tv_find_psw= (TextView) findViewById(R.id.tv_find_psw);
btn_login=(Button) findViewById(R.id.btn_login);
et_user_name=(EditText) findViewById(R.id.et_user_name);
et_psw=(EditText) findViewById(R.id.et_psw);
tv_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LoginActivity.this.finish();
}
});
//立即注冊控件的點擊事件
tv_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(LoginActivity.this,RegisterActivity.class);
startActivityForResult(intent, 1);
}
});
//找回密碼控件的點擊事件
tv_find_psw.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳轉到找回密碼界面(此頁面暫未創建)
}
});
//登錄按鈕的點擊事件
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userName=et_user_name.getText().toString().trim();
psw=et_psw.getText().toString().trim();
String md5Psw= MD5Utils.md5(psw);//對當前用戶輸入的密碼進行MD5加密再進行比對判斷
spPsw=readPsw(userName);//從SharedPreferences中根據用戶名讀取密碼
if(TextUtils.isEmpty(userName)){
Toast.makeText(LoginActivity.this, "請輸入用戶名", Toast.LENGTH_SHORT).show();
return;
}else if(TextUtils.isEmpty(psw)){
Toast.makeText(LoginActivity.this, "請輸入密碼", Toast.LENGTH_SHORT).show();
return;
}else if(md5Psw.equals(spPsw)){
Toast.makeText(LoginActivity.this, "登錄成功", Toast.LENGTH_SHORT).show();
//保存登錄狀態
saveLoginStatus(true, userName);
//登錄成功后關閉此頁面進入主頁
Intent data=new Intent();
data.putExtra("isLogin",true);
setResult(RESULT_OK,data);
LoginActivity.this.finish();
startActivity(new Intent(LoginActivity.this, MainActivity.class));
return;
}else if((spPsw!=null&&!TextUtils.isEmpty(spPsw)&&!md5Psw.equals(spPsw))){
Toast.makeText(LoginActivity.this, "輸入的用戶名和密碼不一致", Toast.LENGTH_SHORT).show();
return;
}else{
Toast.makeText(LoginActivity.this, "此用戶名不存在", Toast.LENGTH_SHORT).show();
}
}
});
}
/**
*從SharedPreferences中根據用戶名讀取密碼
*/
private String readPsw(String userName){
SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
return sp.getString(userName , "");
}
/**
*保存登錄狀態和登錄用戶名到SharedPreferences中
*/
private void saveLoginStatus(boolean status,String userName){
//loginInfo表示文件名
SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
SharedPreferences.Editor editor=sp.edit();//獲取編輯器
editor.putBoolean("isLogin", status);//存入boolean類型的登錄狀態
editor.putString("loginUserName", userName);//存入登錄狀態時的用戶名
editor.commit();//提交修改
}
/**
* 注冊成功的數據返回至此
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(data!=null){
//從注冊界面傳遞過來的用戶名
String userName =data.getStringExtra("userName");
if(!TextUtils.isEmpty(userName)){
et_user_name.setText(userName);
//設置光標的位置
et_user_name.setSelection(userName.length());
}
}
}
}
修改歡迎界面邏輯
將歡迎界面的下一個界面從主頁修改為登錄界面,具體代碼如下:
SplashActivity
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
改為
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);