主頁 > 移動端開發 > android 仿微信小demo(實作移動端,服務端)

android 仿微信小demo(實作移動端,服務端)

2021-06-09 22:33:50 移動端開發

文章目錄

  • 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的底層原理

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more