功能概述
自动验证:输入第6位密码后自动验证。
删除键优化:按下删除键时,如果当前输入框为空,则回退到上一个输入框并清空内容。
密码可见性切换:点击"显示密码"按钮,可以切换密码的可见性。
**震动反馈:**密码错误时提供震动反馈。
输入框抖动动画:密码错误时,输入框抖动提示用户。
实现步骤
布局文件:定义主界面和弹框布局,调整输入框间隙为 3dp。
**样式文件:**为输入框添加边框样式。
动画文件:实现输入框抖动动画。
**逻辑处理:**优化删除键逻辑、自动验证、密码可见性切换等功能。
代码结构
布局文件:
activity_my_number_edit.xml:主界面布局。
dialog_password.xml:密码输入弹框布局。
样式文件:
edittext_border.xml:输入框边框样式。
动画文件:
shake.xml:输入框抖动动画。
逻辑处理:
MyNumberEditActivity.java:实现弹框显示、密码验证、删除键优化等功能。
1. 主界面布局文件 (activity_my_number_edit.xml)
主界面只有一个按钮,点击后弹出密码输入框:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/btnShowPasswordDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="输入密码"/>
</LinearLayout>
2. 密码输入框布局文件 (dialog_password.xml)
弹框布局,密码输入框之间的间隙为 3dp,并支持全屏显示:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center"
android:background="@android:color/white">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入6位密码"
android:textSize="18sp"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/passwordContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<EditText
android:id="@+id/et1"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"
android:layout_marginEnd="3dp"/>
<EditText
android:id="@+id/et2"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"
android:layout_marginEnd="3dp"/>
<EditText
android:id="@+id/et3"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"
android:layout_marginEnd="3dp"/>
<EditText
android:id="@+id/et4"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"
android:layout_marginEnd="3dp"/>
<EditText
android:id="@+id/et5"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"
android:layout_marginEnd="3dp"/>
<EditText
android:id="@+id/et6"
android:layout_width="40dp"
android:layout_height="40dp"
android:maxLength="1"
android:inputType="numberPassword"
android:gravity="center"
android:background="@drawable/edittext_border"/>
</LinearLayout>
<Button
android:id="@+id/btnToggleVisibility"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示密码"
android:layout_marginTop="16dp"/>
</LinearLayout>
3. 输入框边框样式 (edittext_border.xml)
在 res/drawable 目录下创建 edittext_border.xml,用于设置输入框的边框样式:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="1dp" android:color="#000000"/>
<corners android:radius="4dp"/>
</shape>
4. 抖动动画 (res/anim/shake.xml)
在 res/anim 目录下创建 shake.xml,用于实现输入框抖动动画:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="50"
android:fromXDelta="0"
android:toXDelta="10"
android:repeatCount="5"
android:repeatMode="reverse"/>
5. 逻辑处理 (MyNumberEditActivity.java)
以下是完整的逻辑处理代码:
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MyNumberEditActivity extends AppCompatActivity {
private final String CORRECT_PASSWORD = "123456"; // 正确的密码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_number_edit);
findViewById(R.id.btnShowPasswordDialog).setOnClickListener(v -> showPasswordDialog());
}
private void showPasswordDialog() {
// 创建Dialog
final Dialog dialog = new Dialog(this, android.R.style.Theme_NoTitleBar_Fullscreen); // 全屏样式
dialog.setContentView(R.layout.dialog_password);
dialog.setCancelable(true);
// 自动弹出软键盘
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
// 获取Dialog中的控件
EditText[] etPassword = new EditText[6];
etPassword[0] = dialog.findViewById(R.id.et1);
etPassword[1] = dialog.findViewById(R.id.et2);
etPassword[2] = dialog.findViewById(R.id.et3);
etPassword[3] = dialog.findViewById(R.id.et4);
etPassword[4] = dialog.findViewById(R.id.et5);
etPassword[5] = dialog.findViewById(R.id.et6);
Button btnToggleVisibility = dialog.findViewById(R.id.btnToggleVisibility);
// 清空输入框
for (EditText et : etPassword) {
et.setText("");
}
// 设置输入监听
setupTextWatchers(etPassword, dialog);
// 切换密码可见性
btnToggleVisibility.setOnClickListener(v -> togglePasswordVisibility(etPassword, btnToggleVisibility));
// 显示Dialog
dialog.show();
}
private void setupTextWatchers(EditText[] etPassword, Dialog dialog) {
for (int i = 0; i < etPassword.length; i++) {
final int currentIndex = i;
etPassword[i].addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 1 && currentIndex < etPassword.length - 1) {
etPassword[currentIndex + 1].requestFocus(); // 自动跳到下一个输入框
}
// 当第6位输入完成时,自动验证密码
if (currentIndex == etPassword.length - 1 && s.length() == 1) {
String inputPassword = getPassword(etPassword);
if (inputPassword.equals(CORRECT_PASSWORD)) {
Toast.makeText(MyNumberEditActivity.this, "密码正确,进入下一步", Toast.LENGTH_SHORT).show();
dialog.dismiss();
// 这里可以跳转到下一步
} else {
Toast.makeText(MyNumberEditActivity.this, "密码错误,请重试", Toast.LENGTH_SHORT).show();
vibrate(); // 震动反馈
shakeInputs(etPassword); // 输入框抖动动画
clearInput(etPassword); // 清空输入框
etPassword[0].requestFocus(); // 焦点回到第一个输入框
}
}
}
@Override
public void afterTextChanged(Editable s) {}
});
// 处理删除键
etPassword[i].setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
if (etPassword[currentIndex].getText().length() == 0 && currentIndex > 0) {
etPassword[currentIndex - 1].requestFocus(); // 回退到上一个输入框
etPassword[currentIndex - 1].setText(""); // 清空上一个输入框的内容
return true; // 拦截删除键事件
}
}
return false;
});
}
}
private String getPassword(EditText[] etPassword) {
StringBuilder password = new StringBuilder();
for (EditText et : etPassword) {
password.append(et.getText().toString());
}
return password.toString();
}
private void clearInput(EditText[] etPassword) {
for (EditText et : etPassword) {
et.setText("");
}
}
private void vibrate() {
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
vibrator.vibrate(200); // 震动200毫秒
}
}
private void shakeInputs(EditText[] etPassword) {
Animation shake = AnimationUtils.loadAnimation(this, R.anim.shake);
for (EditText et : etPassword) {
et.startAnimation(shake);
}
}
private void togglePasswordVisibility(EditText[] etPassword, Button btnToggleVisibility) {
boolean isVisible = etPassword[0].getInputType() == (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
for (EditText et : etPassword) {
if (isVisible) {
et.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
} else {
et.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
}
}
btnToggleVisibility.setText(isVisible ? "显示密码" : "隐藏密码");
}
}
运行效果
点击主界面的"输入密码"按钮,弹出全屏密码输入框。
依次输入6位数字,输入内容显示为圆点。
当输入第6位时,自动验证密码:
如果密码正确,提示"密码正确,进入下一步",并关闭弹框。
如果密码错误,提示"密码错误,请重试",清空输入框并震动反馈,同时输入框抖动。
支持删除键回退到上一个输入框,并清空上一个输入框的内容。
点击"显示密码"按钮,可以切换密码的可见性。