操作密码
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
package com.example.defenseapplication.view
|
||||
package com.example.defenseapplication.personal
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.text.Editable
|
||||
import android.text.InputFilter
|
||||
import android.text.TextWatcher
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import com.example.defenseapplication.R
|
||||
import com.example.defenseapplication.databinding.DialogPasswordInputBinding
|
||||
@@ -18,6 +23,9 @@ class PasswordInputDialog(context: Context) : Dialog(context) {
|
||||
private var onConfirmListener: ((String) -> Unit)? = null
|
||||
private var onDismissListener: (() -> Unit)? = null
|
||||
|
||||
// 6个密码输入框数组
|
||||
private lateinit var passwordEditTexts: Array<EditText>
|
||||
|
||||
init {
|
||||
initView()
|
||||
}
|
||||
@@ -26,68 +34,204 @@ class PasswordInputDialog(context: Context) : Dialog(context) {
|
||||
binding = DialogPasswordInputBinding.inflate(LayoutInflater.from(context))
|
||||
setContentView(binding.root)
|
||||
|
||||
setCanceledOnTouchOutside(true)
|
||||
|
||||
window?.apply {
|
||||
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
val params = attributes
|
||||
params.gravity = Gravity.CENTER
|
||||
params.width = WindowManager.LayoutParams.MATCH_PARENT
|
||||
// 设置弹窗宽度:屏幕宽度 - 左边距37 - 右边距36
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val screenWidth = displayMetrics.widthPixels
|
||||
params.width = screenWidth - 73 // 37 + 36
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
params.horizontalMargin = 40f
|
||||
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
|
||||
attributes = params
|
||||
}
|
||||
|
||||
// 初始化输入框数组
|
||||
passwordEditTexts = arrayOf(
|
||||
binding.etPwd0,
|
||||
binding.etPwd1,
|
||||
binding.etPwd2,
|
||||
binding.etPwd3,
|
||||
binding.etPwd4,
|
||||
binding.etPwd5
|
||||
)
|
||||
|
||||
setupPasswordInput()
|
||||
|
||||
binding.btnCancel.setOnClickListener {
|
||||
binding.ivClose.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.btnConfirm.setOnClickListener {
|
||||
val password = getPassword()
|
||||
if (password.length == 6) {
|
||||
onConfirmListener?.invoke(password)
|
||||
dismiss()
|
||||
}
|
||||
// 自动弹出键盘
|
||||
binding.root.post {
|
||||
passwordEditTexts[0].requestFocus()
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(passwordEditTexts[0], InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPasswordInput() {
|
||||
val editTexts = listOf(
|
||||
binding.etPassword1,
|
||||
binding.etPassword2,
|
||||
binding.etPassword3,
|
||||
binding.etPassword4,
|
||||
binding.etPassword5,
|
||||
binding.etPassword6
|
||||
)
|
||||
// 为每个输入框设置监听器
|
||||
for (i in passwordEditTexts.indices) {
|
||||
val currentEt = passwordEditTexts[i]
|
||||
|
||||
editTexts.forEachIndexed { index, editText ->
|
||||
editText.setOnKeyListener { _, _, _ ->
|
||||
if (editText.text.isNotEmpty()) {
|
||||
if (index < editTexts.size - 1) {
|
||||
editTexts[index + 1].requestFocus()
|
||||
// 设置只能输入数字
|
||||
currentEt.filters = arrayOf(InputFilter.LengthFilter(1))
|
||||
|
||||
currentEt.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
// 用户手动输入或删除时清除错误
|
||||
if (count > 0 || before > 0) {
|
||||
clearError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val text = s?.toString() ?: ""
|
||||
|
||||
if (text.isNotEmpty()) {
|
||||
// 输入了内容,自动跳转到下一个输入框
|
||||
if (i < passwordEditTexts.size - 1) {
|
||||
// 检查是否按顺序输入:当前位置之前的所有输入框都必须有内容
|
||||
if (isInputInOrder(i)) {
|
||||
passwordEditTexts[i + 1].requestFocus()
|
||||
} else {
|
||||
// 不是按顺序输入,清空当前输入
|
||||
currentEt.text?.clear()
|
||||
}
|
||||
}
|
||||
// 检查是否已输入完6位密码
|
||||
checkPasswordComplete()
|
||||
} else {
|
||||
editText.clearFocus()
|
||||
// 删除了内容,自动跳转到上一个有内容的输入框
|
||||
if (currentEt.hasFocus()) {
|
||||
// 从当前位置往前查找第一个有内容的输入框
|
||||
val previousFilledIndex = findPreviousFilledIndex(i)
|
||||
if (previousFilledIndex >= 0) {
|
||||
passwordEditTexts[previousFilledIndex].requestFocus()
|
||||
// 选中内容,方便继续删除
|
||||
passwordEditTexts[previousFilledIndex].selectAll()
|
||||
} else if (i > 0) {
|
||||
// 如果前面都为空,保持在第一个输入框
|
||||
passwordEditTexts[0].requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 设置键盘监听器,处理当前框为空时按删除键的情况
|
||||
currentEt.setOnKeyListener { _, keyCode, event ->
|
||||
// 只处理删除键按下事件
|
||||
if (keyCode == android.view.KeyEvent.KEYCODE_DEL && event.action == android.view.KeyEvent.ACTION_DOWN) {
|
||||
val currentText = currentEt.text.toString()
|
||||
// 如果当前输入框为空,跳转到上一个有内容的输入框并删除
|
||||
if (currentText.isEmpty() && i > 0) {
|
||||
val previousFilledIndex = findPreviousFilledIndex(i)
|
||||
if (previousFilledIndex >= 0) {
|
||||
// 删除上一个输入框的内容
|
||||
passwordEditTexts[previousFilledIndex].text?.clear()
|
||||
// 继续向前查找下一个有内容的输入框
|
||||
val newPreviousIndex = findPreviousFilledIndex(previousFilledIndex)
|
||||
if (newPreviousIndex >= 0) {
|
||||
passwordEditTexts[newPreviousIndex].requestFocus()
|
||||
passwordEditTexts[newPreviousIndex].selectAll()
|
||||
} else {
|
||||
// 如果前面都为空,定位到第一个输入框
|
||||
passwordEditTexts[0].requestFocus()
|
||||
}
|
||||
return@setOnKeyListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
editText.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) {
|
||||
(v as EditText).setSelection((v.text?.length ?: 0))
|
||||
// 设置触摸监听器,确保按顺序输入
|
||||
currentEt.setOnTouchListener { _, _ ->
|
||||
// 如果不是第一个输入框,检查前面的输入框是否都有内容
|
||||
if (i > 0) {
|
||||
val previousText = passwordEditTexts[i - 1].text.toString()
|
||||
if (previousText.isEmpty()) {
|
||||
// 前面的输入框为空,自动跳转到第一个空的输入框
|
||||
val firstEmptyIndex = findFirstEmptyIndex()
|
||||
if (firstEmptyIndex < i) {
|
||||
passwordEditTexts[firstEmptyIndex].requestFocus()
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否按顺序输入
|
||||
*/
|
||||
private fun isInputInOrder(currentIndex: Int): Boolean {
|
||||
for (i in 0 until currentIndex) {
|
||||
if (passwordEditTexts[i].text.toString().isEmpty()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找第一个空的输入框索引
|
||||
*/
|
||||
private fun findFirstEmptyIndex(): Int {
|
||||
for (i in passwordEditTexts.indices) {
|
||||
if (passwordEditTexts[i].text.toString().isEmpty()) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return passwordEditTexts.size
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定位置往前查找第一个有内容的输入框索引
|
||||
* @param startIndex 开始查找的位置(不包含)
|
||||
* @return 第一个有内容的输入框索引,未找到返回 -1
|
||||
*/
|
||||
private fun findPreviousFilledIndex(startIndex: Int): Int {
|
||||
for (i in startIndex - 1 downTo 0) {
|
||||
if (passwordEditTexts[i].text.toString().isNotEmpty()) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查密码是否输入完成
|
||||
*/
|
||||
private fun checkPasswordComplete() {
|
||||
val password = getPassword()
|
||||
if (password.length == 6) {
|
||||
autoVerifyPassword()
|
||||
}
|
||||
}
|
||||
|
||||
private fun autoVerifyPassword() {
|
||||
val password = getPassword()
|
||||
if (password.length == 6) {
|
||||
onConfirmListener?.invoke(password)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPassword(): String {
|
||||
return binding.etPassword1.text.toString() +
|
||||
binding.etPassword2.text.toString() +
|
||||
binding.etPassword3.text.toString() +
|
||||
binding.etPassword4.text.toString() +
|
||||
binding.etPassword5.text.toString() +
|
||||
binding.etPassword6.text.toString()
|
||||
val sb = StringBuilder()
|
||||
for (et in passwordEditTexts) {
|
||||
sb.append(et.text.toString())
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun setOnConfirmListener(listener: (String) -> Unit): PasswordInputDialog {
|
||||
@@ -103,6 +247,15 @@ class PasswordInputDialog(context: Context) : Dialog(context) {
|
||||
fun showError(message: String) {
|
||||
binding.tvError.text = message
|
||||
binding.tvError.visibility = View.VISIBLE
|
||||
shakePasswordInput()
|
||||
}
|
||||
|
||||
private fun shakePasswordInput() {
|
||||
val shakeAnimation = AnimationUtils.loadAnimation(context, R.anim.shake)
|
||||
// 对每个输入框应用抖动动画
|
||||
for (et in passwordEditTexts) {
|
||||
et.startAnimation(shakeAnimation)
|
||||
}
|
||||
}
|
||||
|
||||
fun clearError() {
|
||||
@@ -111,16 +264,16 @@ class PasswordInputDialog(context: Context) : Dialog(context) {
|
||||
}
|
||||
|
||||
fun clearPassword() {
|
||||
binding.etPassword1.text?.clear()
|
||||
binding.etPassword2.text?.clear()
|
||||
binding.etPassword3.text?.clear()
|
||||
binding.etPassword4.text?.clear()
|
||||
binding.etPassword5.text?.clear()
|
||||
binding.etPassword6.text?.clear()
|
||||
binding.etPassword1.requestFocus()
|
||||
for (et in passwordEditTexts) {
|
||||
et.text?.clear()
|
||||
}
|
||||
passwordEditTexts[0].requestFocus()
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
// 隐藏键盘
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(passwordEditTexts[0].windowToken, 0)
|
||||
super.dismiss()
|
||||
onDismissListener?.invoke()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user