• Android 实战项目:找回密码



    实战项目:找回密码

    在移动互联网时代,用户是每家IT企业最宝贵的资源,对于App而言,吸引用户注册并登录是万分紧要之事,因为用户登录之后才有机会产生商品交易。登录校验通常是用户名+密码组合,可是每天总有部分用户忘记密码,为此要求App提供找回密码的功能,如何简化密码找回步骤,同时兼顾安全性,就是一个值得认真思考的问题。

    一,需求描述

    各家电商App的登录页面大同小异,要么是用户名与密码组合登录,要么是手机号码与验证码组合登录,若是做好一点的,则会提供找回密码与记住密码等功能。先来看一下登录页面是什么样,因为有两种组合登录方式,所以登录页面也分成两个效果图。如图5-37所示,这是选中密码登录时的界面;如图5-38所示,这是选中验证码登录时的界面。
    在这里插入图片描述
    在这里插入图片描述
    从以上两个登录效果图可以看到,密码登录与验证码登录的界面主要存在以下几点区别:
    (1)密码输入框和验证码输入框的左侧标题以及输入框内部的提示语各不相同。
    (2)如果是密码登录,则需要支持找回密码;如果是验证码登录,则需要支持向用户手机发送验证码。
    (3)密码登录可以提供记住密码功能,而验证码的数值每次都不一样,无须也没法记住验证码。
    对于找回密码功能,一般直接跳到找回密码页面,在该页面输入和确认新密码,并校验找回密码的合法性(通过短信验证码检查),据此勾勒出密码找回页面的轮廓概貌,如图5-39所示。

    在这里插入图片描述
    在找回密码的操作过程当中,为了更好地增强用户体验,有必要在几个关键节点处提醒用户。比如成功发送验证码之后,要及时提示用户注意查收短信,这里暂且做成提醒对话框的形式,如图5-40所示。又比如密码登录成功之后,也要告知用户已经修改成功登录,注意继续后面的操作,登录成功的提示弹窗如图5-41所示。
    在这里插入图片描述
    在这里插入图片描述
    真是想不到,原来简简单单的一个登录功能,就得考虑这么多的需求场景。可是仔细想想,这些需求场景都是必要的,其目的是为了让用户能够更加便捷地顺利登录。正所谓“台上十分钟,台下十年功”,每个好用的App背后,都离不开开发者十年如一日的辛勤工作。

    二,界面设计

    用户登录与找回密码界面看似简单,用到的控件却不少。按照之前的界面效果图,大致从上到下、从左到右分布着下列Android控件:

    • 单选按钮RadioButton:用来区分是密码登录还是验证码登录。
    • 文本视图TextView:输入框左侧要显示此处应该输入什么信息。
    • 编辑框EditText:用来输入手机号码、密码和验证码。
    • 复选框CheckBox:用于判断是否记住密码。
    • 按钮Button:除了“登录”按钮,还有“忘记密码”和“获取验证码”两个按钮。
    • 线性布局LinearLayout:整体界面从上往下排列,用到了垂直方向的线性布局。
    • 相对布局RelativeLayout:忘记密码的按钮与密码输入框是叠加的,且“忘记密码”与上级视图右对齐。
    • 单选组RadioGroup:密码登录和验证码登录这两个单选按钮,需要放在单选组之中。
    • 提醒对话框AlertDialog:为了演示方便,获取验证码与登录成功都通过提醒对话框向用户反馈结果。

    另外,由于整个登录模块由登录页面和找回密码页面组成,因此这两个页面之间需要进行数据交互,也
    就是在页面跳转之时传递参数。譬如,从登录页面跳到找回密码页面,要携带唯一标识的手机号码作为
    请求参数,不然密码找回页面不知道要给哪个手机号码修改密码。同时,从找回密码页面回到登录页
    面,也要将修改之后的新密码作为应答参数传回去,否则登录页面不知道密码被改成什么了。

    三,关键代码

    为了方便读者更好更快地完成登录页面与找回密码页面,下面列举几个重要功能的代码片段:

    1)关于自动清空错误的密码

    这里有个细微的用户体验问题:用户会去找回密码,肯定是发现输入的密码不对;那么修改密码后回到
    登录页面,如果密码框里还是刚才的错误密码,用户只能先清空错误密码,然后才能输入新密码。一个
    App要想让用户觉得好用,就得急用户之所急,想用户之所想,像刚才那个错误密码的情况,应当由
    App在返回登录页面时自动清空原来的错误密码。

    自动清空密码框的操作,放在onActivityResult方法中处理是个办法,但这样有个问题,如果用户直接按
    返回键回到登录页面,那么onActivityResult方法发现数据为空便不做处理。因此应该这么处理:判断当
    前是否为返回页面动作,只要是从找回密码页面返回到当前页面,则不管是否携带应答参数,都要自动
    清空密码输入框。对应的Java代码则为重写登录页面的onRestart方法,在该方法中强制清空密码。这样
    一来,不管用户是修改密码完成回到登录页,还是点击返回键回到登录页,App都会自动清空密码框
    了。

    下面是重写onRestart方法之后的代码例子:

    // 从修改密码页面返回登录页面,要清空密码的输入框
    @Override
    protected void onRestart() {
        super.onRestart();
        et_password.setText("");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)关于自动隐藏输入法面板

    在输入手机号码或者密码的时候,屏幕下方都会弹出输入法面板,供用户按键输入数字和字母。但是输入法面板往往占据屏幕下方大块空间,很是碍手碍脚,用户输入完11位的手机号码时,还得再按一下返回键来关闭输入法面板,接着才能继续输入密码。理想的做法是:一旦用户输完11位手机号码,App就要自动隐藏输入法。同理,一旦用户输完6位密码或者6位验证码,App也要自动隐藏输入法。要想让App具备这种智能的判断功能,就得给文本编辑框添加监听器,只要当前编辑框输入文本长度达到11位或者和6位,App就自动隐藏输入法面板。

    下面是实现自动隐藏软键盘的监听器代码例子:

    // 定义一个编辑框监听器,在输入文本达到指定长度时自动隐藏输入法
    private class HideTextWatcher implements TextWatcher {
        private EditText mView; // 声明一个编辑框对象
        private int mMaxLength; // 声明一个最大长度变量
        
        public HideTextWatcher(EditText v, int maxLength) {
            super();
            mView = v;
            mMaxLength = maxLength;
        }
        
        // 在编辑框的输入文本变化前触发
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
        
        // 在编辑框的输入文本变化时触发
        public void onTextChanged(CharSequence s, int start, int before, int count){}
        
        // 在编辑框的输入文本变化后触发
        public void afterTextChanged(Editable s) {
            String str = s.toString(); // 获得已输入的文本字符串
            // 输入文本达到11位(如手机号码),或者达到6位(如登录密码)时关闭输入法
            if ((str.length() == 11 && mMaxLength == 11) || (str.length() == 6 && mMaxLength == 6)) {
                ViewUtil.hideOneInputMethod(LoginMainActivity.this, mView); // 隐藏输入法软键盘
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3)关于密码修改的校验操作

    由于密码对于用户来说是很重要的信息,因此必须认真校验新密码的合法性,务必做到万无一失才行。具体的密码修改校验可分作下列4个步骤:

    1. 新密码和确认输入的新密码都要是6位数字。
    2. 新密码和确认输入的新密码必须保持一致。
    3. 用户输入的验证码必须和系统下发的验证码一致。
    4. 密码修改成功,携带修改后的新密码返回登录页面。

    根据以上的校验步骤,对应的代码逻辑示例如下:

    String password_first = et_password_first.getText().toString();
    String password_second = et_password_second.getText().toString();
    if (password_first.length() < 6 || password_second.length() < 6) {
        Toast.makeText(this, "请输入正确的新密码", Toast.LENGTH_SHORT).show();
        return;
    }
    if (!password_first.equals(password_second)) {
        Toast.makeText(this, "两次输入的新密码不一致", Toast.LENGTH_SHORT).show();
        return;
    }
    if (!et_verifycode.getText().toString().equals(mVerifyCode)) {
        Toast.makeText(this, "请输入正确的验证码", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "密码修改成功", Toast.LENGTH_SHORT).show();
        // 以下把修改好的新密码返回给上一个页面
        Intent intent = new Intent(); // 创建一个新意图
        intent.putExtra("new_password", password_first); // 存入新密码
        setResult(Activity.RESULT_OK, intent); // 携带意图返回上一个页面
        finish(); // 结束当前的活动页面
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    四,详细操作步骤

    1)前期准备

    1.新建一个dimens.xml文件,增加内容如下:
    在这里插入图片描述

    
    <resources>
        <dimen name="common_font_size">17spdimen>
        <dimen name="button_font_size">20spdimen>
        <dimen name="item_layout_height">50dpdimen>
    resources>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.向string.xml增加如下内容:

    <resources>
        <string name="app_name">项目实战:找回密码string>
        <string name="login_by_password">密码登录string>
        <string name="login_by_verifycode">验证码登录string>
        <string name="phone_number">手机号码:string>
        <string name="input_phone_number">请输入手机号码string>
        <string name="login_password">登录密码:string>
        <string name="input_password">请输入密码string>
        <string name="forget_password">忘记密码string>
        <string name="remember_password">记住密码string>
        <string name="login">     string>
        <string name="input_new_password">输入新密码:string>
        <string name="input_new_password_hint">请输入新密码string>
        <string name="confirm_new_password">确认新密码:string>
        <string name="input_new_password_again">请再次输入新密码string>
        <string name="verifycode">    验证码:string>
        <string name="verifycode2">        验证码:string>
        <string name="input_verifycode">请输入验证码string>
        <string name="get_verifycode">获取验证码string>
        <string name="done">     string>
    resources>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.新建LoginMainActivity和LoginForgetActivity活动页面,选中你项目下scr - main - java - 右击 com… - 选择 【New】-【Activity】-【Empty Activity】
    在这里插入图片描述4.在弹出的 New Android Activity 对话框中创建两个活动页面
    在这里插入图片描述
    5.创建完成会自动打开以下文件
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    2)编辑界面代码

    1.activity_login_main.xml文件代码如下:

    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <RadioGroup
            android:id="@+id/rg_login"
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <RadioButton
                android:id="@+id/rb_password"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:checked="true"
                android:text="@string/login_by_password"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <RadioButton
                android:id="@+id/rb_verifycode"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="@string/login_by_verifycode"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
        RadioGroup>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/phone_number"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <EditText
                android:id="@+id/et_phone"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:layout_weight="1"
                android:background="@drawable/editext_selector"
                android:hint="@string/input_phone_number"
                android:inputType="number"
                android:maxLength="11"
                android:textColor="@color/black"
                android:textColorHint="@color/grey"
                android:textSize="@dimen/common_font_size" />
    
    
        LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/tv_password"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/login_password"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <RelativeLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1">
    
                <EditText
                    android:id="@+id/et_password"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginTop="5dp"
                    android:layout_marginBottom="5dp"
                    android:layout_weight="1"
                    android:background="@drawable/editext_selector"
                    android:hint="@string/input_password"
                    android:inputType="numberPassword"
                    android:maxLength="11"
                    android:textColor="@color/black"
                    android:textColorHint="@color/grey"
                    android:textSize="@dimen/common_font_size" />
    
                <Button
                    android:id="@+id/btn_forget"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_alignParentEnd="true"
                    android:text="@string/forget_password"
                    android:textColor="@color/black"
                    android:textSize="@dimen/common_font_size" />
            RelativeLayout>
    
        LinearLayout>
    
        <CheckBox
            android:id="@+id/ck_remember"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:button="@drawable/checkbox_selector"
            android:text="@string/remember_password"
            android:textColor="@color/black"
            android:textSize="@dimen/common_font_size" />
    
        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/login"
            android:textColor="@color/black"
            android:textSize="@dimen/button_font_size" />
    LinearLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127

    效果预览图:
    在这里插入图片描述

    2.activity_login_forget.xml文件代码如下:

    
    <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="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/input_new_password"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <EditText
                android:id="@+id/et_password_first"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:layout_weight="1"
                android:background="@drawable/editext_selector"
                android:hint="@string/input_new_password_hint"
                android:inputType="numberPassword"
                android:maxLength="11"
                android:textColor="@color/black"
                android:textColorHint="@color/grey"
                android:textSize="@dimen/common_font_size" />
    
    
        LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/confirm_new_password"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <EditText
                android:id="@+id/et_password_second"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:layout_weight="1"
                android:background="@drawable/editext_selector"
                android:hint="@string/input_new_password_again"
                android:inputType="numberPassword"
                android:maxLength="11"
                android:textColor="@color/black"
                android:textColorHint="@color/grey"
                android:textSize="@dimen/common_font_size" />
    
    
        LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_layout_height"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/verifycode2"
                android:textColor="@color/black"
                android:textSize="@dimen/common_font_size" />
    
            <RelativeLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1">
    
                <EditText
                    android:id="@+id/et_verifycode"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginTop="5dp"
                    android:layout_marginBottom="5dp"
                    android:layout_weight="1"
                    android:background="@drawable/editext_selector"
                    android:hint="@string/input_verifycode"
                    android:inputType="numberPassword"
                    android:maxLength="11"
                    android:textColor="@color/black"
                    android:textColorHint="@color/grey"
                    android:textSize="@dimen/common_font_size" />
    
                <Button
                    android:id="@+id/btn_verifycode"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_alignParentEnd="true"
                    android:text="@string/get_verifycode"
                    android:textColor="@color/black"
                    android:textSize="@dimen/common_font_size" />
            RelativeLayout>
    
        LinearLayout>
    
        <Button
            android:id="@+id/btn_confirm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/done"
            android:textColor="@color/black"
            android:textSize="@dimen/button_font_size" />
    LinearLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    效果预览图:
    在这里插入图片描述

    3)编辑后台代码

    文件 LoginMainActivity.java 源代码:

    import androidx.activity.result.ActivityResult;
    import androidx.activity.result.ActivityResultCallback;
    import androidx.activity.result.ActivityResultLauncher;
    import androidx.activity.result.contract.ActivityResultContracts;
    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.Activity;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.os.Bundle;
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.view.View;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.EditText;
    import android.widget.RadioButton;
    import android.widget.RadioGroup;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.dongnaoedu.chapter05.util.ViewUtil;
    
    import java.util.Random;
    
    public class LoginMainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener, View.OnClickListener {
    
        private TextView tv_password;
        private EditText et_password;
        private Button btn_forget;
        private CheckBox ck_remember;
        private EditText et_phone;
        private RadioButton rb_password;
        private RadioButton rb_verifycode;
        private ActivityResultLauncher<Intent> register;
        private Button btn_login;
        private String mPassword = "111111";
        private String mVerifyCode;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login_main);
            RadioGroup rb_login = findViewById(R.id.rg_login);
            tv_password = findViewById(R.id.tv_password);
            et_phone = findViewById(R.id.et_phone);
            et_password = findViewById(R.id.et_password);
            btn_forget = findViewById(R.id.btn_forget);
            ck_remember = findViewById(R.id.ck_remember);
            rb_password = findViewById(R.id.rb_password);
            rb_verifycode = findViewById(R.id.rb_verifycode);
            btn_login = findViewById(R.id.btn_login);
            // 给rg_login设置单选监听器
            rb_login.setOnCheckedChangeListener(this);
            // 给et_phone添加文本变更监听器
            et_phone.addTextChangedListener(new HideTextWatcher(et_phone, 11));
            // 给et_password添加文本变更监听器
            et_password.addTextChangedListener(new HideTextWatcher(et_password, 6));
            btn_forget.setOnClickListener(this);
            btn_login.setOnClickListener(this);
    
            register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    Intent intent = result.getData();
                    if (intent != null && result.getResultCode() == Activity.RESULT_OK) {
                        // 用户密码已改为新密码,故更新密码变量
                        mPassword = intent.getStringExtra("new_password");
                    }
                }
            });
        }
    
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            switch (checkedId) {
                // 选择了密码登录
                case R.id.rb_password:
                    tv_password.setText(getString(R.string.login_password));
                    et_password.setHint(getString(R.string.input_password));
                    btn_forget.setText(getString(R.string.forget_password));
                    ck_remember.setVisibility(View.VISIBLE);
                    break;
                // 选择了验证码登录
                case R.id.rb_verifycode:
                    tv_password.setText(getString(R.string.verifycode));
                    et_password.setHint(getString(R.string.input_verifycode));
                    btn_forget.setText(getString(R.string.get_verifycode));
                    ck_remember.setVisibility(View.GONE);
                    break;
            }
        }
    
        @Override
        public void onClick(View v) {
            String phone = et_phone.getText().toString();
            if (phone.length() < 11) {
                Toast.makeText(this, "请输入正确的手机号", Toast.LENGTH_SHORT).show();
                return;
            }
            switch (v.getId()) {
                case R.id.btn_forget:
                    // 选择了密码方式校验,此时要跳到找回密码页面
                    if (rb_password.isChecked()) {
                        // 以下携带手机号码跳转到找回密码页面
                        Intent intent = new Intent(this, LoginForgetActivity.class);
                        intent.putExtra("phone", phone);
                        register.launch(intent);
                    } else if (rb_verifycode.isChecked()) {
                        // 生成六位随机数字的验证码
                        mVerifyCode = String.format("%06d", new Random().nextInt(999999));
                        // 以下弹出提醒对话框,提示用户记住六位验证码数字
                        AlertDialog.Builder buider = new AlertDialog.Builder(this);
                        buider.setTitle("请记住验证码");
                        buider.setMessage("手机号" + phone + ",本次验证码是" + mVerifyCode + ",请输入验证码");
                        buider.setPositiveButton("好的", null);
                        AlertDialog dialog = buider.create();
                        dialog.show();
                    }
                    break;
                case R.id.btn_login:
                    // 密码方式校验
                    if (rb_password.isChecked()) {
                        if (!mPassword.equals(et_password.getText().toString())) {
                            Toast.makeText(this, "请输入正确的密码", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        // 提示用户登录成功
                        loginSuccess();
                    } else if (rb_verifycode.isChecked()) {
                        // 验证码方式校验
                        if (!mVerifyCode.equals(et_password.getText().toString())) {
                            Toast.makeText(this, "请输入正确的验证码", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        // 提示用户登录成功
                        loginSuccess();
                    }
                    break;
            }
        }
    
        // 校验通过,登录成功
        private void loginSuccess() {
            String desc = String.format("您的手机号码是%s,恭喜你通过登录验证,点击“确定”按钮返回上个页面",
                    et_phone.getText().toString());
            // 以下弹出提醒对话框,提示用户登录成功
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("登录成功");
            builder.setMessage(desc);
            builder.setPositiveButton("确定返回", (dialog, which) -> {
                // 结束当前的活动页面
                finish();
            });
            builder.setNegativeButton("我再看看", null);
            AlertDialog dialog = builder.create();
            dialog.show();
        }
    
        // 定义一个编辑框监听器,在输入文本达到指定长度时自动隐藏输入法
        private class HideTextWatcher implements TextWatcher {
            private EditText mView;
            private int mMaxLength;
    
            public HideTextWatcher(EditText v, int maxLength) {
                this.mView = v;
                this.mMaxLength = maxLength;
            }
    
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
    
            }
    
            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() == mMaxLength) {
                    // 隐藏输入法软键盘
                    ViewUtil.hideOneInputMethod(LoginMainActivity.this, mView);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189

    文件 LoginForgetActivity.java 源代码:

    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import java.util.Random;
    
    public class LoginForgetActivity extends AppCompatActivity implements View.OnClickListener {
    
        private String mPhone;
        private String mVerifyCode;
        private EditText et_password_first;
        private EditText et_password_second;
        private EditText et_verifycode;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login_forget);
            et_password_first = findViewById(R.id.et_password_first);
            et_password_second = findViewById(R.id.et_password_second);
            et_verifycode = findViewById(R.id.et_verifycode);
            // 从上一个页面获取要修改密码的手机号码
            mPhone = getIntent().getStringExtra("phone");
    
            findViewById(R.id.btn_verifycode).setOnClickListener(this);
            findViewById(R.id.btn_confirm).setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_verifycode:
                    // 点击了“获取验证码”按钮
                    // 生成六位随机数字的验证码
                    mVerifyCode = String.format("%06d", new Random().nextInt(999999));
                    // 以下弹出提醒对话框,提示用户记住六位验证码数字
                    AlertDialog.Builder buider = new AlertDialog.Builder(this);
                    buider.setTitle("请记住验证码");
                    buider.setMessage("手机号" + mPhone + ",本次验证码是" + mVerifyCode + ",请输入验证码");
                    buider.setPositiveButton("好的", null);
                    AlertDialog dialog = buider.create();
                    dialog.show();
                    break;
    
                case R.id.btn_confirm:
                    // 点击了“确定”按钮
                    String password_first = et_password_first.getText().toString();
                    String password_second = et_password_second.getText().toString();
                    if (password_first.length() < 6) {
                        Toast.makeText(this, "请输入正确的密码", Toast.LENGTH_SHORT).show();
                        return;
                    }
    
                    if (!password_first.equals(password_second)) {
                        Toast.makeText(this, "两次输入的新密码不一致", Toast.LENGTH_SHORT).show();
                        return;
                    }
    
                    if (!mVerifyCode.equals(et_verifycode.getText().toString())) {
                        Toast.makeText(this, "请输入正确的验证码", Toast.LENGTH_SHORT).show();
                        return;
                    }
    
                    Toast.makeText(this, "密码修改成功", Toast.LENGTH_SHORT).show();
                    // 以下把修改好的新密码返回给上一个页面
                    Intent intent = new Intent();
                    intent.putExtra("new_password", password_first);
                    setResult(Activity.RESULT_OK, intent);
                    finish();
                    break;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    4)运行效果

    在这里插入图片描述

    五,总结

    本章主要介绍了App开发的中级控件的相关知识,包括:定制简单的图形(图形的基本概念、形状图形、九宫格图片、状态列表图形)、操纵几种选择按钮(复选框CheckBox、开关按钮Switch、单选按钮RadioButton)、高效地输入文本(编辑框EditText、焦点变更监听器、文本变化监听器)、获取对话框的选择结果(提醒对话框AlertDialog、日期对话框DatePickerDialog、时间对话框TimePickerDialog)。最后设计了一个实战项目“找回密码”,在该项目的App编码中用到了前面介绍的大部分控件,从而加深了对所学知识的理解。

    通过本章的学习,我们应该能掌握以下4种开发技能:
    (1)学会定制几种简单的图形。
    (2)学会操纵常见的选择按钮。
    (3)学会高效且合法地输入文本。
    (4)学会通过对话框获取用户选项。

  • 相关阅读:
    mongodb入门(四)
    ros2_control【B站WMGIII教学学习记录】1
    2024中国眼博会·第六届北京国际青少年眼健康产业展览会
    IDEA Service窗口
    【C/C++】带你快速掌握 使用—增强for(范围for循环)
    【华为机试题分析】 6 质数因子
    122. 买卖股票的最佳时机 II
    TCP数据报结构分析(面试重点)
    Linux篇17多线程第一部分
    在LAXCUS集群里,如何比别人跑得更快?
  • 原文地址:https://blog.csdn.net/m0_62617719/article/details/127657717