Android EditText 输入内容自动添加分割符

package 

import android.text.Editable
import android.text.InputType
import android.text.Selection
import android.text.TextWatcher
import android.text.method.DigitsKeyListener
import android.view.View
import android.widget.EditText
import android.widget.LinearLayout

/**
 * @Author : Forever
 * @Date : on 2024-08-12 16:00.
 * @Description :Edittext 插入一空格监听
 */
open class NumSpaceTextWatcher : TextWatcher {
    // 目标输入框
    private val mDesTxt: EditText

    // 偏移量(几位插入一空格)
    private var mOffset: Int

    //插入的符号
    private var mAddChar: String? = null

    // 记录目标字符串
    private val mBuffer = StringBuffer()

    // 改变之前的文本长度
    private var mBeforeTextLength = 0

    // 改变之后的文本长度
    private var mOnTextLength = 0

    // 改变之前去除空格的文本长度
    private var mBeforeNumTxtLength = 0

    // 改变之后去除空格的文本长度
    private var mNumTxtLength = 0

    // 目标 光标的位置
    private var mLocation = 0

    // 之前 光标的位置(可判断用户是否做删除操作)
    private var mBeforeLocation = 0

    // 改变前有多少空格
    private var mBeforeSpaceNumber = 0

    // 是否选中空格覆盖
    private var isOverrideSpace = false

    // 被覆盖的空格数
    private var mOverrideSpaceNum = 0

    // 是否是粘贴(此粘贴非彼粘贴)
    private var isPaste = false

    // 复制的字符数(不包括空格)
    private var mPasteNum = 0

    // 是否需要进行格式化字符串操作
    private var isChanged = false

    //要处理的View
    private var disposeView: LinearLayout? = null

    private var maxLength: Int = MAX_LENGTH

    @JvmOverloads
    constructor(target: EditText, offset: Int = DEFAULT_OFFSET, limitLength: Int = MAX_LENGTH,char:String? = ' '.toString()) {
        if (target.inputType == InputType.TYPE_CLASS_NUMBER) {
            target.inputType = InputType.TYPE_CLASS_TEXT
            // 当InputType为Number时,手动设置我们的Listener
            target.keyListener = MyDigitsKeyListener()
        } else require(target.inputType == InputType.TYPE_CLASS_TEXT) {
            // 仅支持Text及Number类型的EditText
            "EditText only support TEXT and NUMBER InputTyp!"
        }
        mDesTxt = target
        mOffset = offset
        mAddChar = char
        maxLength = limitLength
    }

    //对特殊的控件要做处理的
    constructor(target: EditText, offset: Int, disposeView: LinearLayout?) {
        if (target.inputType == InputType.TYPE_CLASS_NUMBER) {
            target.inputType = InputType.TYPE_CLASS_TEXT
            // 当InputType为Number时,手动设置我们的Listener
            target.keyListener = MyDigitsKeyListener()
        } else require(target.inputType == InputType.TYPE_CLASS_TEXT) {
            // 仅支持Text及Number类型的EditText
            "EditText only support TEXT and NUMBER InputTyp!"
        }
        mDesTxt = target
        mOffset = offset
        this.disposeView = disposeView
    }

    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
        mBeforeTextLength = s.length
        mBeforeNumTxtLength = s.toString().replace(" ".toRegex(), "").length
        mBeforeLocation = mDesTxt.selectionEnd
        // 重置mBuffer
        if (mBuffer.isNotEmpty()) {
            mBuffer.delete(0, mBuffer.length)
        }
        // 计算改变前空格的个数
        mBeforeSpaceNumber = 0
        for (element in s) {
            if (element.toString().equals(mAddChar)) {
                mBeforeSpaceNumber++
            }
        }
    }

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        mOnTextLength = s.length
        mNumTxtLength = s.toString().replace(" ".toRegex(), "").length
        // 判断是否是粘贴,其中粘贴小于offset位的不做判断,并且offset>2判断才有意义
        if (mOffset >= (mOffset-1) && count >= mOffset) {
            isPaste = true
            mPasteNum = count
        } else {
            isPaste = false
            mPasteNum = 0
        }
        // 若是经过afterTextChanged方法,则直接return
        if (isChanged) {
            isChanged = false
            return
        }
        // 若改变后长度小于等于mOffset - 1,则直接return
        if (mOnTextLength <= mOffset - 1) {
            isChanged = false
            return
        }
        // 若改变前后长度一致,并且数字位数相同,则isChanged为false
        // (数字位数相同是防止用户单选空格后输入数字)
        if (mBeforeTextLength == mOnTextLength && mBeforeNumTxtLength == mNumTxtLength) {
            isChanged = false
            return
        } else {
            isChanged = true
        }
        // 若要进行格式化,则判断该情况
        // 判断是否选中空格覆盖(排除删除空格的情况)
        isOverrideSpace = if (before == 1 && count == 0) {
            false
        } else {
            mBeforeTextLength - mBeforeSpaceNumber - before + count != mNumTxtLength
        }
        // 若是该情况,计算覆盖空格的个数
        mOverrideSpaceNum = if (isOverrideSpace) {
            mNumTxtLength - (mBeforeTextLength - mBeforeSpaceNumber - before + count)
        } else {
            0
        }
    }

    override fun afterTextChanged(s: Editable) {
        if (isChanged) {
            mLocation = mDesTxt.selectionEnd
            // 去除空格
            var text = s.toString().replace(mAddChar?:"", "")
            if (text.length > maxLength) {
                text = text.substring(0, maxLength)
            }
            mBuffer.append(text)
            // 格式化字符串,mOffset位加一个空格
            var index = 0
            var mAfterSpaceNumber = 0
            while (index < mBuffer.length) {
                if (index == mOffset * (1 + mAfterSpaceNumber) + mAfterSpaceNumber) {
                    mBuffer.insert(index, mAddChar)
                    mAfterSpaceNumber++
                }
                index++
            }
            // 判断是否是粘贴键入
            if (isPaste) {
                mLocation += mPasteNum / mOffset
                isPaste = false
                // 判断是否是选中空格输入
            } else if (isOverrideSpace) {
                mLocation += mOverrideSpaceNum
                // 判断此时光标是否在特殊位置上
            } else if (mLocation % (mOffset + 1) == 0) {
                // 是键入OR删除
                if (mBeforeLocation <= mLocation) {
                    mLocation++
                } else {
                    mLocation--
                }
            }
            // 若是删除数据刚好删除一位,前一位是空格,mLocation会超出格式化后字符串的长度(因为格
            // 式化后的长度没有不包括最后的空格),将光标移到正确的位置
            val str = mBuffer.toString()
            if (mLocation > str.length) {
                mLocation = str.length
            } else if (mLocation < 0) {
                mLocation = 0
            }
            s.replace(0, s.length, str)
            val editable = mDesTxt.text
            Selection.setSelection(editable, mLocation)
        }
        if (s.length <= 0 && disposeView != null) {
            disposeView!!.visibility = View.GONE
        }
    }

    // 继承DigitsKeyListener,实现我们自己的Listener
    private inner class MyDigitsKeyListener : DigitsKeyListener() {
        private val mAccepted = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ')

        override fun getAcceptedChars(): CharArray {
            return mAccepted
        }
    }

    companion object {
        private const val DEFAULT_OFFSET = 4

        private const val MAX_LENGTH = 9
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值