文章目錄
- android studio創建移動端專案
- 微信啟動界面
- 顯示頁面延遲activity
- 啟動頁activity
- 測驗
- 注冊功能
- 移動端注冊相關功能實作
- 注冊activity
- 測驗
- 服務端功能實作
- idea創建服務端專案
- 配置tomcat服務器
- 啟動專案測驗服務器
- 創建web層和客戶端完成資料互動
- 創建service層處理業務邏輯功能
- 創建dao層去操作資料庫
- 通過JDBC工具類訪問資料庫
- 通過navicat可視化工具創建資料庫和表
- 測驗注冊功能
- 登錄功能
- 移動端登錄相關功能實作
- 登錄activity
- 測驗
- 服務端功能實作
- 創建web層和客戶端完成資料互動
- 在service層中添加處理業務邏輯功能
- 在dao層添加操作資料庫的功能
- 測驗登錄功能
- 微信四個頁面實作
- 微信四個頁面框架
- 測驗效果
仿微信UI設計,移動端用android studio寫,服務端用idea,
主要功能包括注冊登錄,微信登錄成功后顯示微信首頁(四個頁面),所有功能資料處理都是在服務器中處理,資料也是從服務器獲得(圖片,文字)
android studio創建移動端專案



微信啟動界面
我們啟動微信頁面時會看到有頁面延遲河駁轉到啟動頁面,所以創建的兩個activity要實作這個功能,
顯示頁面延遲activity
創建AppStart.java activity,用于顯示頁面延遲跳轉到啟動頁功能


AppStart.java代碼如下
package com.example.wxchatdemo;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
public class AppStart extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.app_start); //設定布局
//延遲頁面跳轉
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
/*頁面延遲1秒跳轉到微信啟動頁面*/
Intent intent = new Intent(com.example.wxchatdemo.AppStart.this, com.example.wxchatdemo.Welcome.class);
startActivity(intent);
com.example.wxchatdemo.AppStart.this.finish(); //結束當前activity
}
}, 1000);
}
}
創建對應的布局app_start.xml檔案


app_start.xml代碼如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/welcome" >
</LinearLayout>
啟動頁activity
創建上面AppStart跳轉的activity Welcome.java,顯示app啟動頁面及跳轉到兩個頁面(登錄,注冊)的功能
代碼如下
package com.example.wxchatdemo;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class Welcome extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome); //設定布局
}
//登錄按鈕點擊事件處理方法
public void welcome_login(View v) {
Intent intent = new Intent();
/* 頁面跳轉到登錄界面*/
intent.setClass(com.example.wxchatdemo.Welcome.this, Login.class);
startActivity(intent);
this.finish(); //結束當前activity
}
//注冊按鈕點擊事件處理方法
public void welcome_register(View v) {
Intent intent = new Intent();
/*頁面跳轉到注冊界面*/
intent.setClass(com.example.wxchatdemo.Welcome.this, com.example.wxchatdemo.Register.class);
startActivity(intent);
this.finish(); //結束當前activity
}
}
對應的布局welcome.xml檔案如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#eee"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/photoImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:scaleType="fitXY"
android:src="@drawable/wx_login_reigister" />
<Button
android:id="@+id/main_login_btn"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_alignLeft="@id/photoImageView"
android:layout_alignBottom="@id/photoImageView"
android:layout_marginLeft="20dp"
android:layout_marginBottom="20dp"
android:background="@drawable/btn_style_green"
android:onClick="welcome_login"
android:text="登錄"
android:textColor="#ffffff"
android:textSize="18sp" />
<Button
android:id="@+id/main_regist_btn"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_alignRight="@id/photoImageView"
android:layout_alignBottom="@id/photoImageView"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"
android:background="@drawable/btn_style_white"
android:onClick="welcome_register"
android:text="注冊"
android:textColor="#00FF00"
android:textSize="18sp" />
</RelativeLayout>
</LinearLayout>
創建兩個selector選擇器btn_style_green.xml,btn_style_white.xml檔案,用于控制上面welcome.xml布局按鈕的不同狀態


btn_style_green.xml代碼如下
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_style_one_pressed" android:state_focused="false" android:state_pressed="true" />
<item android:drawable="@drawable/btn_style_one_normal" android:state_focused="false" />
</selector>
btn_style_white.xml代碼如下
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_style_two_pressed" android:state_focused="false" android:state_pressed="true" />
<item android:drawable="@drawable/btn_style_two_normal" android:state_focused="false" />
</selector>
在AndroidMainfest.xml檔案中宣告創建的activity


測驗
可以把welcome.java中的跳轉頁面注釋掉,然后啟動專案測驗效果,如下所示


注冊功能
注冊功能主要包括移動端的注冊相關功能(比如界面,向服務器發送http請求)和服務端的表單處理功能,而且服務器的表單驗證的資料要從mysql中獲取
移動端注冊相關功能實作
移動端注冊功能主要包括界面的實作,以及向服務器發送請求,請求成功后跳轉到登錄界面
注冊activity
實作的功能很多,這里例舉幾個(如按鈕是否可點擊,校驗手機號,改變按鈕的狀態需要借助下面要說明的工具類和shape檔案),其他的可以自己運行體會,注釋都有說明,
創建注冊Register.java activity,代碼如下
package com.example.wxchatdemo;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
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.ImageView;
import android.widget.Toast;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Register extends AppCompatActivity {
//宣告組件
private EditText username;
private EditText phone;
private EditText password;
private Button button;
//自定義一個UI修改機制
private MyHander myhander = new MyHander();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.register); //設定布局
/* 隱藏自帶標題*/
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //全屏顯示
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; //因為背景為淺色所以將狀態欄字體設定為黑色
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
initViews(); // 初始化布局元素
// 設定注冊按鈕是否可點擊
if (username.getText() + "" == "" || phone.getText() + "" == "" || password.getText() + "" == "") {
button.setEnabled(false);
} else {
button.setEnabled(true);
}
inputFocus(); //監聽EditView變色
buttonChangeColor(); //登錄按鈕變色
//button的點擊事件事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*判斷輸入的手機號格式對不對,對的話開一個執行緒完成網路請求操作*/
Pattern pattern = Pattern
.compile("^(13[0-9]|15[0-9]|153|15[6-9]|180|18[23]|18[5-9])\\d{8}$");
Matcher matcher = pattern.matcher(phone.getText());
if (matcher.matches()) {
// 開一個執行緒完成網路請求操作
new Thread(new Runnable() {
@Override
public void run() {
httpUrlConnPost(Register.this.username.getText() + "",
phone.getText() + "", password.getText() + "");
}
}).start();
} else {
Toast.makeText(getApplicationContext(), "手機格式錯誤", Toast.LENGTH_LONG).show();
}
}
});
}
/*在這里面獲取到每個需要用到的控制元件的實體*/
@SuppressLint("NewApi")
public void initViews() {
// 得到所有的組件
username = (EditText) this.findViewById(R.id.reg_name);
phone = (EditText) this.findViewById(R.id.reg_phone);
password = (EditText) this.findViewById(R.id.reg_passwd);
button = (Button) this.findViewById(R.id.reg_button);
}
/*監聽EditView變色*/
public void inputFocus() {
username.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver1);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver1);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
phone.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver2);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver2);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
password.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver3);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.reg_diver3);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
}
/*登錄按鈕變色*/
public void buttonChangeColor() {
//創建工具類物件 把要改變顏色的Button先傳過去
WorksSizeCheckUtil.textChangeListener textChangeListener = new WorksSizeCheckUtil.textChangeListener(button);
textChangeListener.addAllEditText(username, phone, password);//把所有要監聽的EditText都添加進去
//介面回呼 在這里拿到boolean變數 根據isHasContent的值決定 Button應該設定什么顏色
WorksSizeCheckUtil.setChangeListener(new IEditTextChangeListener() {
@Override
public void textChange(boolean isHasContent) {
if (isHasContent) {
button.setBackgroundResource(R.drawable.login_button_focus);
button.setTextColor(getResources().getColor(R.color.loginButtonTextFouse));
} else {
button.setBackgroundResource(R.drawable.login_button_shape);
button.setTextColor(getResources().getColor(R.color.loginButtonText));
}
}
});
}
/*發送請求的主要方法*/
public void httpUrlConnPost(String name, String phone, String password) {
HttpURLConnection urlConnection = null;
URL url;
try {
// 請求的URL地地址
url = new URL(
"http://100.2.178.10:8080/AndroidServer_war_exploded/Register");
urlConnection = (HttpURLConnection) url.openConnection();// 打開http連接
urlConnection.setConnectTimeout(3000);// 連接的超時時間
urlConnection.setUseCaches(false);// 不使用快取
// urlConnection.setFollowRedirects(false);是static函式,作用于所有的URLConnection物件,
urlConnection.setInstanceFollowRedirects(true);// 是成員函式,僅作用于當前函式,設定這個連接是否可以被重定向
urlConnection.setReadTimeout(3000);// 回應的超時時間
urlConnection.setDoInput(true);// 設定這個連接是否可以寫入資料
urlConnection.setDoOutput(true);// 設定這個連接是否可以輸出資料
urlConnection.setRequestMethod("POST");// 設定請求的方式
urlConnection.setRequestProperty("Content-Type",
"application/json;charset=UTF-8");// 設定訊息的型別
urlConnection.connect();// 連接,從上述至此的配置必須要在connect之前完成,實際上它只是建立了一個與服務器的TCP連接
JSONObject json = new JSONObject();// 創建json物件
json.put("username", URLEncoder.encode(name, "UTF-8"));// 使用URLEncoder.encode對特殊和不可見字符進行編碼
json.put("phone", URLEncoder.encode(phone, "UTF-8"));
json.put("password", URLEncoder.encode(password, "UTF-8"));// 把資料put進json物件中
String jsonstr = json.toString();// 把JSON物件按JSON的編碼格式轉換為字串
// ------------字符流寫入資料------------
OutputStream out = urlConnection.getOutputStream();// 輸出流,用來發送請求,http請求實際上直到這個函式里面才正式發送出去
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));// 創建字符流物件并用高效緩沖流包裝它,便獲得最高的效率,發送的是字串推薦用字符流,其它資料就用位元組流
bw.write(jsonstr);// 把json字串寫入緩沖區中
bw.flush();// 重繪緩沖區,把資料發送出去,這步很重要
out.close();
bw.close();// 使用完關閉
Log.i("aa", urlConnection.getResponseCode() + "");
//以下判斷是否訪問成功,如果回傳的狀態碼是200則說明訪問成功
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {// 得到服務端的回傳碼是否連接成功
// ------------字符流讀取服務端回傳的資料------------
InputStream in = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = br.readLine()) != null) {// BufferedReader特有功能,一次讀取一行資料
buffer.append(str);
}
in.close();
br.close();
JSONObject rjson = new JSONObject(buffer.toString());
Log.i("aa", "rjson=" + rjson);// rjson={"json":true}
boolean result = rjson.getBoolean("json");// 從rjson物件中得到key值為"json"的資料,這里服務端回傳的是一個boolean型別的資料
System.out.println("json:===" + result);
//如果服務器端回傳的是true,則說明注冊成功,否則注冊失敗
if (result) {// 判斷結果是否正確
//在Android中http請求,必須放到執行緒中去作請求,但是在執行緒中不可以直接修改UI,只能通過hander機制來完成對UI的操作
myhander.sendEmptyMessage(1);
Log.i("用戶:", "注冊成功");
} else {
myhander.sendEmptyMessage(2);
Log.i("用戶:", "注冊失敗");
}
} else {
myhander.sendEmptyMessage(2);
}
} catch (Exception e) {
e.printStackTrace();
Log.i("aa", e.toString());
myhander.sendEmptyMessage(2);
} finally {
urlConnection.disconnect();// 使用完關閉TCP連接,釋放資源
}
}
// 在Android中不可以在執行緒中直接修改UI,只能借助Handler機制來完成對UI的操作
class MyHander extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//判斷hander的內容是什么,如果是1則說明注冊成功,如果是2說明注冊失敗
switch (msg.what) {
case 1:
Log.i("aa", msg.what + "");
Toast.makeText(getApplicationContext(), "注冊成功",
Toast.LENGTH_SHORT).show();
/*跳轉到登錄頁面*/
Intent intent = new Intent();
intent.setClass(com.example.wxchatdemo.Register.this, Login.class);
startActivity(intent);
com.example.wxchatdemo.Register.this.finish(); //結束當前activity
break;
case 2:
Log.i("aa", msg.what + "");
//這是一個提示訊息
Toast.makeText(getApplicationContext(), "注冊失敗", Toast.LENGTH_LONG).show();
}
}
}
//回傳按鈕處理事件
public void rigister_activity_back(View v) {
/*跳轉到微信啟動頁*/
Intent intent = new Intent();
intent.setClass(com.example.wxchatdemo.Register.this, Welcome.class);
startActivity(intent);
com.example.wxchatdemo.Register.this.finish(); //結束當前activity
}
}
上面有個介面和介面的實作類(工具類),實作按鈕在不同輸入框輸入條件的狀態變化,創建工具類WorksSizeCheckUtil.java代碼如下
package com.example.wxchatdemo;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.widget.Button;
import android.widget.EditText;
public class WorksSizeCheckUtil {
static IEditTextChangeListener mChangeListener;
public static void setChangeListener(IEditTextChangeListener changeListener) {
mChangeListener = changeListener;
}
//檢測輸入框是否都輸入了內容 從而改變按鈕的是否可點擊
public static class textChangeListener {
private Button button;
private EditText[] editTexts;
public textChangeListener(Button button) {
this.button = button;
}
public textChangeListener addAllEditText(EditText... editTexts) {
this.editTexts = editTexts;
initEditListener();
return this;
}
private void initEditListener() {
//呼叫了遍歷editext的方法
for (EditText editText : editTexts) {
editText.addTextChangedListener(new textChange());
}
}
// edit輸入的變化來改變按鈕的是否點擊
private class textChange implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (checkAllEdit()) {
//所有EditText有值了
mChangeListener.textChange(true);
button.setEnabled(true);
} else {
//所有EditText值為空
button.setEnabled(false);
mChangeListener.textChange(false);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
}
//檢查所有的edit是否輸入了資料
private boolean checkAllEdit() {
for (EditText editText : editTexts) {
if (!TextUtils.isEmpty(editText.getText() + "")) {
continue;
} else {
return false;
}
}
return true;
}
}
}
介面IEditTextChangeListener.java
package com.example.wxchatdemo;
public interface IEditTextChangeListener {
void textChange(boolean isHasContent);
}
創建上面工具類WorksSizeCheckUtil.java用到的兩個shape檔案,設定按鈕不同狀態,


shapre檔案login_button_focus.xml代碼如下
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/loginButtonBackgroundFouse" /><!-- 填充的顏色 -->
<!-- 設定按鈕的四個角為弧形 -->
<!-- android:radius 弧形的半徑 -->
<corners
android:bottomLeftRadius="6dp"
android:bottomRightRadius="6dp"
android:topLeftRadius="6dp"
android:topRightRadius="6dp" />
<!-- 邊框粗細及顏色 -->
</shape>
shapre檔案login_button_shape,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/loginButtonBackgroundNotFouse" /><!-- 填充的顏色 -->
<!-- 設定按鈕的四個角為弧形 -->
<!-- android:radius 弧形的半徑 -->
<corners
android:bottomLeftRadius="6dp"
android:bottomRightRadius="6dp"
android:topLeftRadius="6dp"
android:topRightRadius="6dp" />
<!-- 邊框粗細及顏色 -->
</shape>
創建上面Register.java activity的布局檔案register.xml,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/title"
android:orientation="vertical">
<ImageView
android:layout_width="17dp"
android:layout_height="17dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="45dp"
android:onClick="rigister_activity_back"
android:src="@drawable/backpay" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="25dp"
android:text="手機號注冊"
android:textColor="@color/loginText"
android:textSize="25sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="昵稱"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/reg_name"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:background="@null"
android:hint="例如:陳晨"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<ImageView
android:id="@+id/reg_diver1"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="手機號"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/reg_phone"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="36dp"
android:background="@null"
android:hint="請填寫手機號"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<ImageView
android:id="@+id/reg_diver2"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="密碼"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/reg_passwd"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:background="@null"
android:hint="請填寫密碼"
android:singleLine="true"
android:password="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<ImageView
android:id="@+id/reg_diver3"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center_horizontal">
<Button
android:id="@+id/reg_button"
android:layout_width="321dp"
android:layout_height="48dp"
android:background="@drawable/login_button_shape"
android:text="注冊"
android:textColor="@color/loginButtonText"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
創建上面布局register.xml檔案用到shape檔案edit_cursor_color.xml,改變游標的顏色,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size android:width="1dp" />
<size android:height="10dp"/>
<solid android:color="@color/loginButtonBackgroundFouse" />
</shape>
在color.xml中添加用到的顏色,代碼如下
<color name="loginButtonBackgroundNotFouse">#D4D8D5</color>
<color name="loginButtonText">#B5B2B2</color>
<color name="title">#EDEDED</color>
<color name="loginText">#5A5959</color>
<color name="textColorHint">#DDDDDD</color>
<color name="loginButtonBackgroundFouse">#07C160</color>
<color name="input_dvier">#D8D8D8</color>
<color name="input_dvier_focus">#1BB879</color>
<color name="loginButtonTextFouse">#FFFFFF</color>
在AndroidMainfest.xml中宣告注冊activity,如下

測驗
因為注冊成功跳轉的登錄activity還沒寫,所以要注釋掉
把上面注冊Register.java activity注冊成功跳轉Login.java activity的代碼段注釋掉后運行專案測驗,如下

因為服務端還沒寫所以注冊失敗
服務端功能實作
通過web層完成客戶端和服務端的資料互動(接受資料,發送資料),service層完成業務邏輯(注冊,登錄),dao層操作資料庫(要借助工具類)
idea創建服務端專案



配置tomcat服務器


啟動專案測驗服務器



創建web層和客戶端完成資料互動
創建Servlet Register.java


Register.java代碼如下
package com.example.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.pojo.User;
import com.example.service.UserService;
import com.example.service.UserServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
@WebServlet(name = "Register", value = "/Register")
public class Register extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* 設定中文字符編碼,防止亂碼*/
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("UTF-8");
//以json資料完成操作
response.setContentType("application/json;charset=UTF-8");
System.out.println(request.getContentType());// 得到客戶端發送過來內容的型別,application/json;charset=UTF-8
System.out.println(request.getRemoteAddr());// 得到客戶端的ip地址,
BufferedReader br = new BufferedReader(new InputStreamReader(// 使用字符流讀取客戶端發過來的資料
request.getInputStream()));
String line = null;
StringBuffer s = new StringBuffer();//StringBuffer String的區別,如果要對資料作頻繁的修改,則用StringBuffer
// 以一行的形式讀取資料
while ((line = br.readLine()) != null) {
s.append(line);
}
// 關閉io流
br.close();
System.out.println(s.toString());
//JSON:這是json決議包,idea是沒有的,要我們自己匯入
User user = JSON.parseObject(s.toString(), User.class);//是用了發射機制來完成物件的封閉
//以utf-8解碼操作
String username = URLDecoder.decode(user.getUsername(), "utf-8");
String phone = URLDecoder.decode(user.getPhone(), "utf-8");
String password = URLDecoder.decode(user.getPassword(), "utf-8");
System.out.println("用戶名是:" + username + ", 密碼;" + password);
System.out.println(user);
// 去資料庫完成用戶注冊功能
UserService us = new UserServiceImpl();
//呼叫注冊的方法
int i = us.registerUser(username, phone, password);
boolean rs = false;
//判斷是否注冊成功
if (i > 0) {
System.out.println("注冊成功");
rs = true;
}
//將結果回傳給客戶端 ,將結果構建成json資料回傳給客戶端
JSONObject rjson = new JSONObject();
rjson.put("json", rs);
response.getOutputStream().write(
rjson.toString().getBytes("UTF-8"));// 向客戶端發送一個帶有json物件內容的回應
}
}
創面Servlet用到的物體類先創建包


后創建類


User.java,代碼如下
package com.example.pojo;
public class User {
private int id;
private String username;
private String phone;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", phone='" + phone + '\'' +
", password='" + password + '\'' +
'}';
}
}
下載JSON決議jar包
下載地址 :https://pan.baidu.com/s/131P_eiT7-57X1CaMyehICg(提取碼:zdou)
在WEB-INF目錄下創建lib資源庫


把下載好的JSON包復制到lib目錄下

把jar包添加到類別庫

創建service層處理業務邏輯功能
創建介面,用到面向介面編程思想,方便添加其他業務功能,因為我們后面還添加其他功能(比如登錄)
在上面創建Servlet Rigister.java檔案中報紅的地方按alt+enter鍵創建介面,如下

放到單獨的包里

創建介面的實作類


在介面里寫個注冊的抽象方法

在實作類中重寫介面方法


然后在實作類中修改代碼如下所示
package com.example.service;
public class UserServiceImpl implements UserService {
UserDao ud = new UserDaoImpl();
@Override
public int registerUser(String username, String phone, String password) {
int i = ud.insertUser(username, phone, password);
return i;
}
}
創建dao層去操作資料庫
創建dao層介面,原理和service層一樣,面向抽象編程


創建介面的實作類


在介面寫把資料插入資料庫的抽象方法

在實作類中重寫介面方法


然后實作類中修改代碼如下所示
package com.example.dao;
public class UserDaoImpl implements UserDao {
@Override
public int insertUser(String username, String phone, String password) {
String sql = "insert into user (username, phone, password) values(?,?,?);";
//i如果操作成功,就是操作成功的條數
int i = JDBCUtil.executeUpdate(sql,username,phone,password);
return i;
}
}
通過JDBC工具類訪問資料庫
創建一個包單獨存放工具類

創建工具類JDBCUtil.java代碼如下
package com.example.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCUtil {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://127.0.0.1:3306/androiddb1?useUnicode=true&characterEncoding=utf-8";
private static final String USER = "root";
private static final String PASSWORD = "root";
private static Connection ct;
private static PreparedStatement ps;
private static ResultSet rs;
static {
// 1.加載驅動,只需要加載一次,所以放到靜態代碼塊中
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 描述:封裝一個方法可以獲得連接,目的可以在其他地方之接呼叫
*/
public static Connection getConnection() {
try {
ct = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ct;
}
/**
* 描述:封裝一個方法可以完成查詢操作
*
* @param sql 要查詢的sql陳述句
* @param obj 占位符的具體內容
* @return ResultSet 將查詢到的結果回傳
*/
public static ResultSet executeQuery(String sql, Object... obj) {
// 1.得到連接
ct = getConnection();
// 2.創鍵發送物件
try {
ps = ct.prepareStatement(sql);
// 處理占位符問題
if (obj != null) {
for (int i = 0; i < obj.length; i++) {
ps.setObject(i + 1, obj[i]);
}
}
rs = ps.executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
/**
* 描述:封裝一個方法可以完成DDL,DML操作
*
* @param sql 要操作的sql陳述句
* @param obj 占位符
* @return
*/
public static int executeUpdate(String sql, Object... obj) {
// 1.得到連接
ct = getConnection();
// 2.創鍵發送物件
try {
ps = ct.prepareStatement(sql);
// 處理占位符問題
if (obj != null) {
for (int i = 0; i < obj.length; i++) {
ps.setObject(i + 1, obj[i]);
}
}
int in = ps.executeUpdate();
close(ct, ps, null);
return in;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
/**
* 描述:封裝一個關閉資源的方法
*
* @param ct 連接物件
* @param ps 發送sql陳述句物件
* @param rs 回傳值物件
*/
public static void close(Connection ct, PreparedStatement ps, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ct != null) {
try {
ct.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 給外部一個訪問ct,和ps的方法
public static Connection getCt() {
return ct;
}
public static PreparedStatement getPs() {
return ps;
}
}
匯入驅動包

把驅動包添加到類別庫,跟上面的JSON包添加一樣的
通過navicat可視化工具創建資料庫和表
我的資料庫名為androiddb1,表名user,可以自己定義

測驗注冊功能
在客戶端的注冊activity中有個請求服務器的方法,里面要把URL的ip地址修改成自己的ip地址,如下所示

查看ip地址的方法,win+R,輸入cmd進入命令列,然后輸入ipconfig,如下所示


把資料庫密碼和資料庫名改為自己的

由于登錄功能還沒實作,所以要把注冊成功跳轉的頁面注釋掉,如下

發布服務端專案

啟動移動端專案

測驗效果

此時資料庫已成功寫入資料

登錄功能
登錄功能主要包括移動端的登錄相關功能(比如界面,向服務器發送http請求)和服務端的表單處理功能,而且服務器的表單驗證的資料要從mysql中獲取,即和注冊類似
移動端登錄相關功能實作
移動端登錄功能主要包括界面的實作,以及向服務器發送請求,請求成功后跳轉到微信首頁
登錄activity
微信的登錄界面有兩個,分別為手機號登錄,微信號登錄,所以要創建兩個activity
創建通過用戶名登錄的LoginUser.java activity 代碼如下
package com.example.wxchatdemo;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBar;
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.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class LoginUser extends AppCompatActivity {
//宣告組件變數
private EditText username;
private EditText password;
private TextView phone_login;
private Button button;
//自定義的一個Hander訊息機制
private MyHander myhander = new MyHander();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_user); //設定布局
/* 隱藏自帶標題*/
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //全屏顯示
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; //因為背景為淺色所以將狀態欄字體設定為黑色
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
initViews(); // 初始化布局元素
// 設定注冊按鈕是否可點擊
if (username.getText() + "" == "" || password.getText() + "" == "") {
button.setEnabled(false);
} else {
button.setEnabled(true);
}
inputFocus(); //監聽EditView變色
buttonChangeColor(); //登錄按鈕變色
// 設定手機號登錄的監聽器
phone_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳轉到手機號登錄的activity
Intent intent=new Intent(LoginUser.this,LoginPhone.class);
startActivity(intent);
}
});
//button的點擊事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//創建一個進度條的activity,通過AndroidMainfest.xml檔案宣告為對胡框,這樣activity就不會覆寫當前的activity
Intent intent = new Intent();
intent.setClass(LoginUser.this, Loading.class);
startActivity(intent);
// 開一個執行緒完成網路請求操作
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
httpUrlConnPost(LoginUser.this.username.getText() + "",
password.getText() + "");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
});
}
@SuppressLint("NewApi")
public void initViews() {
// 得到所有的組件
username = (EditText) this.findViewById(R.id.log_name);
password = (EditText) this.findViewById(R.id.log_passwd);
phone_login = (TextView) this.findViewById(R.id.phone_log);
button = (Button) this.findViewById(R.id.log_button);
}
public void inputFocus() {
username.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver1);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver1);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
password.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver2);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver2);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
}
public void buttonChangeColor() {
//創建工具類物件 把要改變顏色的Button先傳過去
WorksSizeCheckUtil.textChangeListener textChangeListener = new WorksSizeCheckUtil.textChangeListener(button);
textChangeListener.addAllEditText(username, password);//把所有要監聽的EditText都添加進去
//介面回呼 在這里拿到boolean變數 根據isHasContent的值決定 Button應該設定什么顏色
WorksSizeCheckUtil.setChangeListener(new IEditTextChangeListener() {
@Override
public void textChange(boolean isHasContent) {
if (isHasContent) {
button.setBackgroundResource(R.drawable.login_button_focus);
button.setTextColor(getResources().getColor(R.color.loginButtonTextFouse));
} else {
button.setBackgroundResource(R.drawable.login_button_shape);
button.setTextColor(getResources().getColor(R.color.loginButtonText));
}
}
});
}
// 發送請求的主要方法
public void httpUrlConnPost(String name, String password) {
HttpURLConnection urlConnection = null;
URL url;
try {
// 請求的URL地地址
url = new URL(
"http://100.2.178.10:8080/AndroidServer_war_exploded/Login");
urlConnection = (HttpURLConnection) url.openConnection();// 打開http連接
urlConnection.setConnectTimeout(3000);// 連接的超時時間
urlConnection.setUseCaches(false);// 不使用快取
// urlConnection.setFollowRedirects(false);是static函式,作用于所有的URLConnection物件,
urlConnection.setInstanceFollowRedirects(true);// 是成員函式,僅作用于當前函式,設定這個連接是否可以被重定向
urlConnection.setReadTimeout(3000);// 回應的超時時間
urlConnection.setDoInput(true);// 設定這個連接是否可以寫入資料
urlConnection.setDoOutput(true);// 設定這個連接是否可以輸出資料
urlConnection.setRequestMethod("POST");// 設定請求的方式
urlConnection.setRequestProperty("Content-Type",
"application/json;charset=UTF-8");// 設定訊息的型別
urlConnection.connect();// 連接,從上述至此的配置必須要在connect之前完成,實際上它只是建立了一個與服務器的TCP連接
JSONObject json = new JSONObject();// 創建json物件
json.put("username", URLEncoder.encode(name, "UTF-8"));// 使用URLEncoder.encode對特殊和不可見字符進行編碼
json.put("password", URLEncoder.encode(password, "UTF-8"));// 把資料put進json物件中
String jsonstr = json.toString();// 把JSON物件按JSON的編碼格式轉換為字串
// ------------字符流寫入資料------------
OutputStream out = urlConnection.getOutputStream();// 輸出流,用來發送請求,http請求實際上直到這個函式里面才正式發送出去
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));// 創建字符流物件并用高效緩沖流包裝它,便獲得最高的效率,發送的是字串推薦用字符流,其它資料就用位元組流
bw.write(jsonstr);// 把json字串寫入緩沖區中
bw.flush();// 重繪緩沖區,把資料發送出去,這步很重要
out.close();
bw.close();// 使用完關閉
Log.i("aa", urlConnection.getResponseCode() + "");
//以下判斷是否訪問成功,如果回傳的狀態碼是200則說明訪問成功
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {// 得到服務端的回傳碼是否連接成功
// ------------字符流讀取服務端回傳的資料------------
InputStream in = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = br.readLine()) != null) {// BufferedReader特有功能,一次讀取一行資料
buffer.append(str);
}
in.close();
br.close();
JSONObject rjson = new JSONObject(buffer.toString());
Log.i("aa", "rjson=" + rjson);// rjson={"json":true}
boolean result = rjson.getBoolean("json");// 從rjson物件中得到key值為"json"的資料,這里服務端回傳的是一個boolean型別的資料
System.out.println("json:===" + result);
//如果服務器端回傳的是true,則說明注冊成功,否則注冊失敗
if (result) {// 判斷結果是否正確
//在Android中http請求,必須放到執行緒中去作請求,但是在執行緒中不可以直接修改UI,只能通過hander機制來完成對UI的操作
myhander.sendEmptyMessage(1);
Log.i("用戶:", "登錄成功");
} else {
myhander.sendEmptyMessage(2);
System.out.println("222222222222222");
Log.i("用戶:", "登錄失敗");
}
} else {
myhander.sendEmptyMessage(2);
}
} catch (Exception e) {
e.printStackTrace();
Log.i("aa", e.toString());
System.out.println("11111111111111111");
myhander.sendEmptyMessage(2);
} finally {
urlConnection.disconnect();// 使用完關閉TCP連接,釋放資源
}
}
// 在Android中不可以在執行緒中直接修改UI,只能借助Handler機制來完成對UI的操作
class MyHander extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//判斷hander的內容是什么,如果是1則說明登錄成功,如果是2說明登錄失敗
switch (msg.what) {
case 1:
Log.i("aa", msg.what + "");
//提示
Toast.makeText(getApplicationContext(), "登錄成功",
Toast.LENGTH_SHORT).show();
break;
case 2:
Log.i("aa", msg.what + "");
//對話框
new AlertDialog.Builder(com.example.wxchatdemo.LoginUser.this)
.setTitle(" 登錄失敗")
.setMessage(" 用戶名或密碼錯誤,請重新填寫")
.setPositiveButton("確定", null)
.show();
break;
}
}
}
//回傳按鈕處理事件
public void login_activity_back(View v) {
/*跳轉到微信啟動頁*/
Intent intent = new Intent();
intent.setClass(com.example.wxchatdemo.LoginUser.this, Welcome.class);
startActivity(intent);
com.example.wxchatdemo.LoginUser.this.finish(); //結束當前activity
}
}
創建對應的布局login_user.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/title"
android:orientation="vertical">
<!--回傳按鈕-->
<ImageView
android:id="@+id/close"
android:layout_width="17dp"
android:layout_height="17dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="45dp"
android:onClick="login_activity_back"
android:src="@drawable/backpay" />
<!--標題-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="45dp"
android:text="微信號/QQ號/郵箱登錄"
android:textColor="@color/loginText"
android:textSize="25sp" />
<!--賬號輸入-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="賬號"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/log_name"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:background="@null"
android:hint="請填寫微信號/QQ號/郵箱"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<!--下劃線-->
<ImageView
android:id="@+id/login_diver1"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="密碼"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/log_passwd"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:background="@null"
android:hint="請填寫密碼"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<!--下劃線-->
<ImageView
android:id="@+id/login_diver2"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/phone_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:text="用手機號登錄"
android:textColor="@color/massageLogin"
android:textSize="17dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center_horizontal">
<!--登錄按鈕-->
<Button
android:id="@+id/log_button"
android:layout_width="321dp"
android:layout_height="48dp"
android:background="@drawable/login_button_shape"
android:text="登錄"
android:textColor="@color/loginButtonText"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:divider="@drawable/login_dvier"
android:gravity="center_horizontal"
android:showDividers="middle">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="找回密碼"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="緊急凍結"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="微信安全中心"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>
創建上面布局檔案用到的login_diver.xml shape檔案,實作豎直分割線效果,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@color/login_dvier" />
<size android:height="1dp"></size>
<size android:width="1dp"></size>
</shape>
創建通過手機號登錄的LoginPhone.java activity 代碼如下
package com.example.wxchatdemo;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBar;
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.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class LoginPhone extends AppCompatActivity {
//宣告組件變數
private EditText phone;
private EditText password;
private TextView user_login;
private Button button;
//自定義的一個Hander訊息機制
private LoginPhone.MyHander myhander = new LoginPhone.MyHander();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_phone); //設定布局
/* 隱藏自帶標題*/
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //全屏顯示
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; //因為背景為淺色所以將狀態欄字體設定為黑色
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
initViews(); // 初始化布局元素
// 設定注冊按鈕是否可點擊
if (phone.getText() + "" == "" || password.getText() + "" == "") {
button.setEnabled(false);
} else {
button.setEnabled(true);
}
inputFocus(); //監聽EditView變色
buttonChangeColor(); //登錄按鈕變色
//設定通過微信號登錄的監聽器
user_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳轉到用微信號登錄的activity
Intent intent = new Intent(LoginPhone.this, LoginUser.class);
startActivity(intent);
}
});
//button的點擊事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//創建一個進度條的activity,通過AndroidMainfest.xml檔案宣告為對胡框,這樣activity就不會覆寫當前的activity
Intent intent = new Intent();
intent.setClass(LoginPhone.this, com.example.wxchatdemo.LoadingActivity.class);
startActivity(intent);
// 開一個執行緒完成網路請求操作
new Thread(new Runnable() {
@Override
public void run() {
httpUrlConnPost(LoginPhone.this.phone.getText() + "",
password.getText() + "");
}
}).start();
}
});
}
@SuppressLint("NewApi")
public void initViews() {
// 得到所有的組件
phone = (EditText) this.findViewById(R.id.log_phone);
password = (EditText) this.findViewById(R.id.log_passwd);
user_login = (TextView) this.findViewById(R.id.user_log);
button = (Button) this.findViewById(R.id.log_button);
}
public void inputFocus() {
phone.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver1);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver1);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
password.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 此處為得到焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver2);
imageView.setBackgroundResource(R.color.input_dvier_focus);
} else {
// 此處為失去焦點時的處理內容
ImageView imageView = (ImageView) findViewById(R.id.login_diver2);
imageView.setBackgroundResource(R.color.input_dvier);
}
}
});
}
public void buttonChangeColor() {
//創建工具類物件 把要改變顏色的Button先傳過去
WorksSizeCheckUtil.textChangeListener textChangeListener = new WorksSizeCheckUtil.textChangeListener(button);
textChangeListener.addAllEditText(phone, password);//把所有要監聽的EditText都添加進去
//介面回呼 在這里拿到boolean變數 根據isHasContent的值決定 Button應該設定什么顏色
WorksSizeCheckUtil.setChangeListener(new IEditTextChangeListener() {
@Override
public void textChange(boolean isHasContent) {
if (isHasContent) {
button.setBackgroundResource(R.drawable.login_button_focus);
button.setTextColor(getResources().getColor(R.color.loginButtonTextFouse));
} else {
button.setBackgroundResource(R.drawable.login_button_shape);
button.setTextColor(getResources().getColor(R.color.loginButtonText));
}
}
});
}
// 發送請求的主要方法
public void httpUrlConnPost(String phone, String password) {
HttpURLConnection urlConnection = null;
URL url;
try {
// 請求的URL地地址
url = new URL(
"http://100.2.178.10:8080/AndroidServer_war_exploded/Login");
urlConnection = (HttpURLConnection) url.openConnection();// 打開http連接
urlConnection.setConnectTimeout(3000);// 連接的超時時間
urlConnection.setUseCaches(false);// 不使用快取
// urlConnection.setFollowRedirects(false);是static函式,作用于所有的URLConnection物件,
urlConnection.setInstanceFollowRedirects(true);// 是成員函式,僅作用于當前函式,設定這個連接是否可以被重定向
urlConnection.setReadTimeout(3000);// 回應的超時時間
urlConnection.setDoInput(true);// 設定這個連接是否可以寫入資料
urlConnection.setDoOutput(true);// 設定這個連接是否可以輸出資料
urlConnection.setRequestMethod("POST");// 設定請求的方式
urlConnection.setRequestProperty("Content-Type",
"application/json;charset=UTF-8");// 設定訊息的型別
urlConnection.connect();// 連接,從上述至此的配置必須要在connect之前完成,實際上它只是建立了一個與服務器的TCP連接
JSONObject json = new JSONObject();// 創建json物件
json.put("username", URLEncoder.encode(phone, "UTF-8"));// 使用URLEncoder.encode對特殊和不可見字符進行編碼
json.put("password", URLEncoder.encode(password, "UTF-8"));// 把資料put進json物件中
String jsonstr = json.toString();// 把JSON物件按JSON的編碼格式轉換為字串
// ------------字符流寫入資料------------
OutputStream out = urlConnection.getOutputStream();// 輸出流,用來發送請求,http請求實際上直到這個函式里面才正式發送出去
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));// 創建字符流物件并用高效緩沖流包裝它,便獲得最高的效率,發送的是字串推薦用字符流,其它資料就用位元組流
bw.write(jsonstr);// 把json字串寫入緩沖區中
bw.flush();// 重繪緩沖區,把資料發送出去,這步很重要
out.close();
bw.close();// 使用完關閉
Log.i("aa", urlConnection.getResponseCode() + "");
//以下判斷是否訪問成功,如果回傳的狀態碼是200則說明訪問成功
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {// 得到服務端的回傳碼是否連接成功
// ------------字符流讀取服務端回傳的資料------------
InputStream in = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = br.readLine()) != null) {// BufferedReader特有功能,一次讀取一行資料
buffer.append(str);
}
in.close();
br.close();
JSONObject rjson = new JSONObject(buffer.toString());
Log.i("aa", "rjson=" + rjson);// rjson={"json":true}
boolean result = rjson.getBoolean("json");// 從rjson物件中得到key值為"json"的資料,這里服務端回傳的是一個boolean型別的資料
System.out.println("json:===" + result);
//如果服務器端回傳的是true,則說明登錄成功,否則登錄失敗
if (result) {// 判斷結果是否正確
//在Android中http請求,必須放到執行緒中去作請求,但是在執行緒中不可以直接修改UI,只能通過hander機制來完成對UI的操作
myhander.sendEmptyMessage(1);
Log.i("用戶:", "登錄成功");
} else {
myhander.sendEmptyMessage(2);
System.out.println("222222222222222");
Log.i("用戶:", "登錄失敗");
}
} else {
myhander.sendEmptyMessage(2);
}
} catch (Exception e) {
e.printStackTrace();
Log.i("aa", e.toString());
System.out.println("11111111111111111");
myhander.sendEmptyMessage(2);
} finally {
urlConnection.disconnect();// 使用完關閉TCP連接,釋放資源
}
}
// 在Android中不可以在執行緒中直接修改UI,只能借助Handler機制來完成對UI的操作
class MyHander extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//判斷hander的內容是什么,如果是1則說明注冊成功,如果是2說明注冊失敗
switch (msg.what) {
case 1:
Log.i("aa", msg.what + "");
Toast.makeText(getApplicationContext(), "登錄成功",
Toast.LENGTH_SHORT).show();
break;
case 2:
Log.i("aa", msg.what + "");
new AlertDialog.Builder(com.example.wxchatdemo.LoginPhone.this)
.setTitle(" 登錄失敗")
.setMessage(" 用戶名或密碼錯誤,請重新填寫")
.setPositiveButton("確定", null)
.show();
}
}
}
//回傳按鈕處理事件
public void login_activity_back(View v) {
/*跳轉到微信啟動頁*/
Intent intent = new Intent();
intent.setClass(com.example.wxchatdemo.LoginPhone.this, Welcome.class);
startActivity(intent);
com.example.wxchatdemo.LoginPhone.this.finish(); //結束當前activity
}
}
創建對應的布局login_phone.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/title"
android:orientation="vertical">
<!--回傳按鈕-->
<ImageView
android:id="@+id/close"
android:layout_width="17dp"
android:layout_height="17dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="45dp"
android:onClick="login_activity_back"
android:src="@drawable/backpay" />
<!--標題-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="45dp"
android:text="手機號登錄"
android:textColor="@color/loginText"
android:textSize="25sp" />
<!--賬號輸入-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="手機號"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/log_phone"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="35dp"
android:background="@null"
android:hint="請填寫手機號"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<!--下劃線-->
<ImageView
android:id="@+id/login_diver1"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="密碼"
android:textColor="@color/loginText"
android:textSize="16sp" />
<EditText
android:id="@+id/log_passwd"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:background="@null"
android:hint="請填寫密碼"
android:singleLine="true"
android:textColorHint="@color/textColorHint"
android:textCursorDrawable="@drawable/edit_cursor_color"
android:textSize="16sp" />
</LinearLayout>
<!--下劃線-->
<ImageView
android:id="@+id/login_diver2"
android:layout_width="320dp"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="17dp"
android:background="@color/input_dvier" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/user_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:text="用微信號/QQ號/郵箱登錄"
android:textColor="@color/massageLogin"
android:textSize="17dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center_horizontal">
<!--登錄按鈕-->
<Button
android:id="@+id/log_button"
android:layout_width="321dp"
android:layout_height="48dp"
android:background="@drawable/login_button_shape"
android:text="登錄"
android:textColor="@color/loginButtonText"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:divider="@drawable/login_dvier"
android:gravity="center_horizontal"
android:showDividers="middle">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="找回密碼"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="緊急凍結"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:text="微信安全中心"
android:textColor="@color/massageLogin"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>
上面兩個登錄activity都實作了一個自定義的等待框activity,但是自定義的activity會覆寫原有的界面,因為微信點擊登錄按鈕后會彈出一個等待框且不會覆寫原有的activity(即原有界面),所以要給自定義的等待框activity在Androidfest.xml檔案配置為等待框,這樣就不會覆寫原有activity.
創建Loading.java activity,實作自定義等待框,代碼如下
package com.example.wxchatdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
public class Loading extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.loading); //設定布局
//一秒后結束當前activity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Loading.this.finish();
}
}, 1000);
}
}
對應的布局loading.xml檔案,代碼如下
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_centerInParent="true"
android:background="@drawable/loading_bg">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="正在登錄"
android:textColor="#fff"
android:textSize="20sp" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
在AndroidMainfest.xml檔案中配置自定義等待框Loading.java activity為對話框,添加如下代碼
<activity android:name=".Loading" android:theme="@style/MyDialogStyle"/>
上面用到的主題是自定義的主題,要自己定義,創建樣式styles.xml檔案,如下


在上面styles.xml檔案添加如下代碼,使自定義的等待框activity變為對話框
<style name="MyDialogStyle">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
在colors.xml檔案中定義上面所以檔案用到的顏色,添加如下代碼
<color name="massageLogin">#5A6A8B</color>
<color name="login_dvier">#BEBEBE</color>
在AndroidMainfest.xml檔案中宣告activity,如下

測驗
因為服務端表單驗證功能還沒寫,所以登錄會失敗的,但是還是可以測驗上面的效果
啟動移動端專案,測驗效果如下

服務端功能實作
通過web層完成客戶端和服務端的資料互動(接受資料,發送資料),service層完成業務邏輯(注冊,登錄),dao層操作資料庫(要借助工具類)
創建web層和客戶端完成資料互動
創建Servlet Login.java 代碼如下
package com.example.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.pojo.User;
import com.example.service.UserServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
@WebServlet(name = "Login", value = "/Login")
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//設定字符編碼,防止中文亂碼
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("UTF-8");
//以json資料完成操作
response.setContentType("application/json;charset=UTF-8");
System.out.println(request.getContentType());// 得到客戶端發送過來內容的型別,application/json;charset=UTF-8
System.out.println(request.getRemoteAddr());// 得到客戶端的ip地址,
BufferedReader br = new BufferedReader(new InputStreamReader(// 使用字符流讀取客戶端發過來的資料
request.getInputStream()));
String line = null;
StringBuffer s = new StringBuffer();//StringBuffer String的區別,如果要對資料作頻繁的修改,則用StringBuffer
// 以一行的形式讀取資料
while ((line = br.readLine()) != null) {
s.append(line);
}
// 關閉io流
br.close();
System.out.println(s.toString());// {"password":"123456","name":"admin"}
//JSON:這是json決議包,IDEA是沒有,要我們自己匯入
User user = JSON.parseObject(s.toString(), User.class);//是用了反射機制來完成物件的封閉
//以utf-8解碼操作
String username = URLDecoder.decode(user.getUsername(), "utf-8");
String password = URLDecoder.decode(user.getPassword(), "utf-8");
System.out.println("用戶名是:" + username + ", 密碼;" + password);
System.out.println(user);
// 去資料庫完成用戶登錄功能
UserServiceImpl us = new UserServiceImpl();
//呼叫登錄的方法
User user1 = us.login(username, password);
boolean loginInfo = false;
if (user1 != null) {
//登錄成功
loginInfo = true;
}
//將結果回傳給客戶端,將結果構建成json資料回傳給客戶端
JSONObject rjson = new JSONObject();
rjson.put("json", loginInfo);
response.getOutputStream().write(
rjson.toString().getBytes("UTF-8"));// 向客戶端發送一個帶有json物件內容的回應
}
}
在service層中添加處理業務邏輯功能
service層我們在注冊已經寫過了,只需要添加一個登錄處理功能即可
在上面創建service層的UserService介面中添加登錄的抽象方法,如下
User login(String username,String password);

在實作類UserServiceImpl中重寫介面方法,如下
@Override
public User login(String username, String password) {
//呼叫dao層完成資料查詢操作
User user = ud.findByUsername(username);
if (user != null) {
//比較密碼
if (password.equals(user.getPassword())) {
//登錄成功
return user;
}
}
return null;
}

在dao層添加操作資料庫的功能
在介面UserDao中添加把資料添加到資料庫的抽象方法,如下
//查詢用戶通過username
User findByUsername(String username);

實作類重寫介面方法,如下
@Override
public User findByUsername(String username) {
//判斷資料是用戶名還是手機
Pattern pattern = Pattern
.compile("^(13[0-9]|15[0-9]|153|15[6-9]|180|18[23]|18[5-9])\\d{8}$");
Matcher matcher = pattern.matcher(username);
//手機sql執行陳述句
if (matcher.matches()) {
//sql
String sql = "select * from user where phone=?";
rs = JDBCUtil.executeQuery(sql, username);
} else { //用戶名sql執行陳述句
//sql
String sql = "select * from user where username=?";
rs = JDBCUtil.executeQuery(sql, username);
}
//判斷是否查詢到用戶
try {
if (rs.next()) {
//如果查詢到用戶,將用戶封裝到User物件中
int id = rs.getInt("id");
String username1 = rs.getString("username");
String password = rs.getString("password");
//將查詢到的用戶封裝到一個User物件中
User user = new User();
user.setId(id);
user.setUsername(username);
user.setPassword(password);
System.out.println("查詢到的用戶" + user);
return user;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
測驗登錄功能

微信四個頁面實作
在微信中可以通過點擊下面的導航按鈕選擇對應的顯示界面,也可以通過滑動界面(fragment)來實作界面切換,同時下面的導航按鈕狀態也會發生變化,頂部是一個操作欄(包括搜索搜索框和選單)第四個頁面沒有這個操作欄,中間是listview,listview資料(圖片,訊息)要動態從服務器獲取,
微信四個頁面框架
可以實作通過點擊微信下方導航或滑動屏切換頁面,上面頂部操作欄只是實作UI界面,沒有實作事件處理(不能點擊),中間先用TextView測驗效果,后面會換成listview并把資料寫活(從服務器獲取圖片和資料)
創建主布局檔案main_weixin.xml,直接部署ViewPager以及下方的導航布局,代碼如下
<?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_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.wxchatdemo.MainWeixin">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DEDEDE"
android:orientation="horizontal"
android:padding="5dp">
<LinearLayout
android:id="@+id/weixin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/weixin_img"
android:layout_width="30dp"
android:layout_height="25dp"
android:background="@drawable/weixin_picture_selector" />
<TextView
android:id="@+id/weixin_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="微信"
android:textColor="@drawable/wenxin_text_selector"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/contact"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/contact_img"
android:layout_width="30dp"
android:layout_height="25dp"
android:background="@drawable/address_picture_selector" />
<TextView
android:id="@+id/contact_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="通訊錄"
android:textColor="@drawable/wenxin_text_selector"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/find"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/find_img"
android:layout_width="30dp"
android:layout_height="25dp"
android:background="@drawable/find_pricture_selector" />
<TextView
android:id="@+id/find_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="發現"
android:textColor="@drawable/wenxin_text_selector"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/self"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/self_img"
android:layout_width="30dp"
android:layout_height="25dp"
android:background="@drawable/settings_pricture_selector" />
<TextView
android:id="@+id/self_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="我"
android:textColor="@drawable/wenxin_text_selector"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
創建四個fragment布局,對應四個頁面
微信訊息fragment布局weixin_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DEDEDE"
android:paddingTop="30dp"
android:paddingBottom="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="150dp"
android:layout_weight="1"
android:text=" 微信"
android:textColor="@color/black"
android:textSize="20sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/search" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/plus" />
</LinearLayout>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="微信訊息"
android:textSize="50sp" />
</LinearLayout>
聯系人fragment布局檔案contaclist_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DEDEDE"
android:paddingTop="30dp"
android:paddingBottom="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="150dp"
android:layout_weight="1"
android:text="通信錄"
android:textColor="@color/black"
android:textSize="20sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/search" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/plus" />
</LinearLayout>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="聯系人"
android:textSize="50sp" />
</LinearLayout>
發現fragment布局檔案find_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DEDEDE"
android:paddingTop="30dp"
android:paddingBottom="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="150dp"
android:layout_weight="1"
android:text=" 發現"
android:textColor="@color/black"
android:textSize="20sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/search" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:maxHeight="23dp"
android:src="@drawable/plus" />
</LinearLayout>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="發現"
android:textSize="50sp" />
</LinearLayout>
個人訊息fragment布局檔案self_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="個人資訊"
android:gravity="center"
android:textSize="50sp"/>
</LinearLayout>
上面四個fragment布局中間都是用TextView,只是為了演示效果,后面會換成listview,并把資料寫活(從資料庫獲取)
設定下方導航組件不同的形態
導航組件中文字形態變化只是顏色不同,通過選擇器selector即可實作
創建選擇器weixin_text_selector.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#66CD00" android:state_selected="true" />
<item android:color="@color/black" android:state_selected="false" />
</selector>
圖片的話需要設定點擊前后不同的圖片,需要創建四個選擇器
創建選擇器weixin_picture_selector.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_weixin_pressed" android:state_selected="true" />
<item android:drawable="@drawable/tab_weixin_normal" android:state_selected="false" />
</selector>
創建選擇器address_picture_selector.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_address_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/tab_address_normal" android:state_selected="false" />
</selector>
創建選擇器find_picture_selector.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_find_frd_pressed" android:state_selected="true" />
<item android:drawable="@drawable/tab_find_frd_normal" android:state_selected="false" />
</selector>
創建選擇器settings_picture_selector.xml檔案,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_settings_pressed" android:state_selected="true" />
<item android:drawable="@drawable/tab_settings_normal" android:state_selected="false" />
</selector>
創建對應四個fragment布局的四個Fragment繼承類
WeixinFragment.java
package com.example.wxchatdemo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class WeixinFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.weixin_fragment, container, false);
return view;
}
}
ContactListFragment.java
package com.example.wxchatdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ContactListFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.contactlist_fragment, container, false);
return view;
}
}
FindFragment.java
package com.example.wxchatdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FindFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.find_fragment, container, false);
return view;
}
}
SelfFragment.java
package com.example.wxchatdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class SelfFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.self_fragment, container, false);
return view;
}
}
創建主布局對應的activity MainWeixin.java
package com.example.wxchatdemo;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MainWeixin extends AppCompatActivity implements View.OnClickListener {
//宣告存盤fragment的集合
private ArrayList<Fragment> fragments;
//宣告四個導航對應fragment
WeixinFragment weixinFragment;
ContactListFragment contactListFragment;
FindFragment findFragment;
SelfFragment selfFragment;
//宣告ViewPager
private ViewPager viewPager;
FragmentManager fragmentManager;//宣告fragment管理
//宣告導航欄中對應的布局
private LinearLayout weixin, contact, find, self;
//宣告導航欄中包含的imageview和textview
private ImageView weixin_img, contact_img, find_img, self_img;
private TextView weixin_txt, contact_txt, find_txt, self_txt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_weixin);
/* 隱藏自帶標題*/
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //全屏顯示
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; //因為背景為淺色所以將狀態欄字體設定為黑色
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
//初始化加載首頁布局
initView();
//呼叫自定義initListener方法,為各個組件添加監聽事件
initListener();
//設定默認選擇的pager和導航欄的狀態
viewPager.setCurrentItem(0);
weixin_img.setSelected(true);
weixin_txt.setSelected(true);
}
private void initListener() {
//為四大導航組件添加監聽
weixin.setOnClickListener(this);
contact.setOnClickListener(this);
find.setOnClickListener(this);
self.setOnClickListener(this);
//為viewpager添加頁面變化的監聽以及事件處理
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//根據位置直接決定顯示哪個fragment
viewPager.setCurrentItem(position);
switch (position) {
case 0:
weixin_img.setSelected(true);
weixin_txt.setSelected(true);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case 1:
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(true);
contact_txt.setSelected(true);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case 2:
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(true);
find_txt.setSelected(true);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case 3:
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(true);
self_txt.setSelected(true);
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void initView() {
//在主布局中根據id找到ViewPager
viewPager = (ViewPager) findViewById(R.id.viewPager);
//實體化所屬四個fragment
weixinFragment = new WeixinFragment();
contactListFragment = new ContactListFragment();
findFragment = new FindFragment();
selfFragment = new SelfFragment();
fragments = new ArrayList<>();
//添加fragments到集合中
fragments.add(weixinFragment);
fragments.add(contactListFragment);
fragments.add(findFragment);
fragments.add(selfFragment);
fragmentManager = getSupportFragmentManager();
//為ViewPager設定配接器用于部署fragments
viewPager.setAdapter(new MyFragmentPagerAdapter(fragmentManager));
weixin = (LinearLayout) findViewById(R.id.weixin);
contact = (LinearLayout) findViewById(R.id.contact);
find = (LinearLayout) findViewById(R.id.find);
self = (LinearLayout) findViewById(R.id.self);
weixin_img = (ImageView) findViewById(R.id.weixin_img);
contact_img = (ImageView) findViewById(R.id.contact_img);
find_img = (ImageView) findViewById(R.id.find_img);
self_img = (ImageView) findViewById(R.id.self_img);
weixin_txt = (TextView) findViewById(R.id.weixin_txt);
contact_txt = (TextView) findViewById(R.id.contact_txt);
find_txt = (TextView) findViewById(R.id.find_txt);
self_txt = (TextView) findViewById(R.id.self_txt);
}
/**
* 設定導航欄的點擊事件并同步更新對應的ViewPager
* 點擊事件其實就是更改導航布局中對應的Text/ImageView
* 的選中狀態,配合drable中的selector更改圖片以及文字變化
*
*
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.weixin:
viewPager.setCurrentItem(0);
weixin_img.setSelected(true);
weixin_txt.setSelected(true);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case R.id.contact:
viewPager.setCurrentItem(1);
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(true);
contact_txt.setSelected(true);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case R.id.find:
viewPager.setCurrentItem(2);
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(true);
find_txt.setSelected(true);
self_img.setSelected(false);
self_txt.setSelected(false);
break;
case R.id.self:
viewPager.setCurrentItem(3);
weixin_img.setSelected(false);
weixin_txt.setSelected(false);
contact_img.setSelected(false);
contact_txt.setSelected(false);
find_img.setSelected(false);
find_txt.setSelected(false);
self_img.setSelected(true);
self_txt.setSelected(true);
break;
}
}
//創建FragmentPagerAdapter
class MyFragmentPagerAdapter extends FragmentPagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
測驗效果
在兩個登錄activity中登錄成功后的代碼段添加跳轉的activity,如下
Intent intent = new Intent (com.example.wxchatdemo.LoginUser.this, com.example.wxchatdemo.MainWeixin.class);
startActivity(intent);
com.example.wxchatdemo.LoginUser.this.finish();

在AndroidMainfest.xml中宣告activity

啟動服務端和客戶端專案測驗

先告一段落,后面在更新四個頁面以及資料動態從服務器獲取,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/286356.html
標籤:其他
上一篇:Android進階知識——Android執行緒和執行緒池
下一篇:iOS之深入決議KVO的底層原理
