android 字母验证码,android kotlin 验证码输入框(自定义View)

需求限制输入长度

输入字符下有下划线

有光标闪烁

触摸时自动弹出输入法

和editText一样有hint 提示语

输入完毕回调

因为需求要求不是很多,所以暂时实现的比较简单

实现语言//首先创建一个class 继承View/**

* 密码输入框

* 支持多位

*/class InputKeyWordView : View, View.OnFocusChangeListener {

interface OnKeyWordChangedListener {

fun onkeyWordChange(keyWord: String, keyWordView: InputKeyWordView)

}

companion object {

private val defaultTxtColr: Int = Color.parseColor("#1A1A1A")

private val defaultHintColor: Int = Color.parseColor("#9B9B9B")

private val defaultCursorColor: Int = Color.parseColor("#9B9B9B")

}    /**

* 输入类型

*/

interface InputType {

companion object {

val NUMBER: Int

get() = 0x11

val NUMBER_CHAR: Int

get() = 0x12

}

}    class InputMatch {

companion object {

private val number_reg = "\\d"

private val numberChar_reg = "\\w"

val patternNumber = Pattern.compile(number_reg)

val patternCharNumber = Pattern.compile(numberChar_reg)

}

}    //msgWhat

private val alphaMsg = 0x111

val mHandler: Handler = @SuppressLint("HandlerLeak")

object : Handler() {

override fun handleMessage(msg: Message) {            if (msg.what == alphaMsg) {

onMessage()

}

}

}

private fun onMessage() {

animEnableShow = !animEnableShow

postInvalidate()

mHandler.sendEmptyMessageDelayed(alphaMsg, ALPHA_ANIM_DELAY)

}    //闪动间隔时间

private val ALPHA_ANIM_DELAY: Long = 800

//光标 宽度

private val cursorWidth: Float    //光标颜色

var cursorColor: Int

set(value) {

field = value

cursorPaint.color = cursorColor

invalidate()

}    //   是否 底部线

var showBottomLine: Boolean

set(value) {

field = value

invalidate()

}    //底部线的颜色

var bottomLineColor: Int

set(value) {

field = value

linePaint.color = bottomLineColor

invalidate()

}    //底部线的高度

var bottomLineHeight: Float

set(value) {

field = value

invalidate()

}    //提示字

var hint: String

set(value) {

field = value

hintPaint.getTextBounds(hint, 0, hint.length, hintBounds)

invalidate()

}    //hint颜色

var hintColor: Int

set(value) {

field = value

hintPaint.color = hintColor

invalidate()

}    //字的颜色

var txtColor: Int

set(value) {

field = value

txtPaint.color = txtColor

invalidate()

}    //字体大小

var txtSize: Float

set(value) {

field = value

hintPaint.textSize = txtSize

txtPaint.textSize = txtSize

invalidate()

}    /**

*  输入类型

*  [InputKeyWordView.InputType]

*/

var inputType: Int

set(value) {

field = value

invalidate()

}    //输入位数

var inputLength: Int

set(value) {

field = value

invalidate()

}    //    =================================

private val hintPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

private var txtPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

private var linePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

style = Paint.Style.FILL

}

private var cursorPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

style = Paint.Style.FILL

}

private val lineInteval: Int    /**

* 闪动第几个 下划线

*///    private var alphaLine = 0

//是否闪动

private var alphaEnable = false

private var animEnableShow = true

//文字大小

private val hintBounds = Rect()    //输入的文字大小

private val inputBounds = Rect()    //输入的字符

private val inputCharArray = StringBuilder()

private val inputMethodManager: InputMethodManager    // 输入完成监听

var onKeyWordChangedListener: OnKeyWordChangedListener? = null

constructor(context: Context) : this(context, null)

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {

val typedArray = context.obtainStyledAttributes(attrs, R.styleable.InputKeyWordView)

showBottomLine = typedArray.getBoolean(R.styleable.InputKeyWordView_ipv_show_bottom_line, true)

bottomLineColor = typedArray.getColor(R.styleable.InputKeyWordView_ipv_bottom_line_color, defaultHintColor)

bottomLineHeight = typedArray.getDimension(R.styleable.InputKeyWordView_ipv_bottom_line_height, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, context.resources.displayMetrics))

hintColor = typedArray.getColor(R.styleable.InputKeyWordView_ipv_hint_color, defaultHintColor)

txtColor = typedArray.getColor(R.styleable.InputKeyWordView_ipv_show_txt_color, defaultTxtColr)

txtSize = typedArray.getDimension(R.styleable.InputKeyWordView_ipv_txt_size, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14f, context.resources.displayMetrics))

hint = typedArray.getString(R.styleable.InputKeyWordView_ipv_hint_text) ?: String()

cursorColor = typedArray.getColor(R.styleable.InputKeyWordView_ipv_cursor_color, defaultCursorColor)

inputType = typedArray.getInt(R.styleable.InputKeyWordView_ipv_input_type, InputType.NUMBER)

inputLength = typedArray.getInt(R.styleable.InputKeyWordView_ipv_input_length, 6)

typedArray.recycle()

isFocusable = true

onFocusChangeListener = this

inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager        //下划线和文字间隔

lineInteval = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, resources.displayMetrics).toInt()

cursorWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, resources.displayMetrics)        //=========================//        hintPaint.color = hintColor//        hintPaint.textSize = txtSize        txtPaint.color = txtColor//        txtPaint.textSize = txtSize        linePaint.color = bottomLineColor//        linePaint.style = Paint.Style.FILL//        hintPaint.getTextBounds(hint, 0, hint.length, hintBounds)

}    /**

* 清除已输入的字符

*/

public fun clearInputKeyWord() {        if (inputCharArray.isNotEmpty()) {

inputCharArray.delete(0, inputCharArray.lastIndex)

drawHint = true

invalidate()

}

}    //获取输入的

public fun getInputKeyWord(): String {        return inputCharArray.toString()

}

override fun onCheckIsTextEditor(): Boolean {        return true

}

override fun onFocusChange(v: View, hasFocus: Boolean) {

alphaEnable = hasFocus        if (hasFocus) {

mHandler.sendEmptyMessageDelayed(alphaMsg, ALPHA_ANIM_DELAY)

openKeyBroad()

} else {

mHandler.removeMessages(alphaMsg)

closeKeyBroad()

}

println("onFocusChange:::::::$hasFocus")

}

private fun openKeyBroad() {

inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)

}

private fun closeKeyBroad() {

inputMethodManager.hideSoftInputFromInputMethod(windowToken, InputMethodManager.HIDE_IMPLICIT_ONLY)

}//重写onCreateInputConnection 用来设置与键盘的链接

override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {

println("onCreateInputConnection")

outAttrs.inputType = when (inputType) {

InputType.NUMBER -> EditorInfo.TYPE_CLASS_NUMBER

InputType.NUMBER_CHAR -> EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD            else -> EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD

}//BaseInputConnection 是View 内 用来处理 键盘输入的类

return object : BaseInputConnection(this, false) {

override fun commitText(text: CharSequence, newCursorPosition: Int): Boolean {//                println("commitText:::::::" + text)

if (when (inputType) {

InputType.NUMBER -> {

InputMatch.patternNumber.matcher(text).matches()

}

InputType.NUMBER_CHAR -> {

InputMatch.patternCharNumber.matcher(text).matches()

}                            else -> false

}) {

addKey(text)

}                return true

}

override fun sendKeyEvent(event: KeyEvent): Boolean {                if (event.action == KeyEvent.ACTION_UP) {

when (event.keyCode) {

KeyEvent.KEYCODE_ENTER -> {

closeKeyBroad()

}

KeyEvent.KEYCODE_DEL -> {

deleteKey()

}

}

}                return super.sendKeyEvent(event)

}

}

}//模拟点击时  获取焦点  弹起键盘

override fun performClick(): Boolean {

isFocusableInTouchMode = true

requestFocus()

openKeyBroad()        return super.performClick()

}//这里 监听手势,按下时开始处理

@SuppressLint("ClickableViewAccessibility")

override fun onTouchEvent(event: MotionEvent): Boolean {        if (event.action == MotionEvent.ACTION_DOWN) {

isFocusableInTouchMode = true

requestFocus()

openKeyBroad()

}        return super.onTouchEvent(event)

}//添加输入的字符  放入 字符数组内

private fun addKey(key: CharSequence) {        if (inputCharArray.length 

drawHint = false

inputCharArray.append(key)//            alphaLine = inputCharArray.length

invalidate()            if (null != onKeyWordChangedListener) {

onKeyWordChangedListener?.onkeyWordChange(inputCharArray.toString(), this)

}

}

}// 每次点击删除键  删除输入的字符

private fun deleteKey() {        if (inputCharArray.isNotEmpty()) {

drawHint = false

inputCharArray.deleteCharAt(inputCharArray.lastIndex)//            alphaLine = inputCharArray.length

invalidate()

}        if (inputCharArray.isEmpty()) {//            alphaLine = 0

drawHint = true

invalidate()

}        if (null != onKeyWordChangedListener) {

onKeyWordChangedListener?.onkeyWordChange(inputCharArray.toString(), this)

}

}

@SuppressLint("SwitchIntDef")

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec))

}    //测量宽度

private fun measureWidth(widthMeasureSpec: Int): Int {

val widthMode = MeasureSpec.getMode(widthMeasureSpec)

var width = suggestedMinimumWidth

val size = MeasureSpec.getSize(widthMeasureSpec)

when (widthMode) {        //View想要到多少就到多少,没有限制

MeasureSpec.AT_MOST                //未指定大小,任意//                , MeasureSpec.UNSPECIFIED

-> {

width = MeasureSpec.getSize(MeasureSpec.AT_MOST)

}        //View指定大小

MeasureSpec.EXACTLY -> {

width = size

}        //        //任意大小

MeasureSpec.UNSPECIFIED -> {

width = Math.max(width, size)

}

}        return width

}

private fun measureHeight(widthMeasureSpec: Int): Int {

val heightMode = MeasureSpec.getMode(widthMeasureSpec)

var height = suggestedMinimumHeight

val size = MeasureSpec.getSize(widthMeasureSpec)

when (heightMode) {        //根据自己的视图决定,想到多少就到多少

MeasureSpec.AT_MOST                //未指定大小//                , MeasureSpec.UNSPECIFIED

-> {

height = hintBounds.height() + paddingTop + paddingBottom + lineInteval

}        //指定高度

MeasureSpec.EXACTLY -> {

height = size

}        //未指定,任意大小

MeasureSpec.UNSPECIFIED -> {                //取最大值

height = Math.max(height, size)

}

}        return height

}

private var drawHint: Boolean = true

override fun onDraw(canvas: Canvas) {        if (drawHint) {

drawHintTxt(canvas)

}

drawInputChar(canvas)

drawBottomLine(canvas)

}    //输入的字符

private fun drawInputChar(canvas: Canvas) {

val eachWidth = (measuredWidth - lineInteval * (inputLength - 1)) / inputLength        for (index in 0..inputLength) {            if (inputCharArray.length > index) {

val char = inputCharArray[index].toString()

txtPaint.getTextBounds(char, 0, char.length, inputBounds)

val y: Float = ((measuredHeight + inputBounds.height()) / 2).toFloat() - txtPaint.fontMetrics.bottom / 2

//中间点x

val startX: Float = (eachWidth / 2 + index * (lineInteval + eachWidth) - inputBounds.width() / 2).toFloat()

canvas.drawText(char

, 0

, char.length

, startX

, y

, txtPaint)

} else break

}

}    //底部下划线 和光标

private fun drawBottomLine(canvas: Canvas) {

val eachWidth = (measuredWidth - lineInteval * (inputLength - 1)) / inputLength

val y = (measuredHeight - paddingBottom - bottomLineHeight)

val bottom = y + bottomLineHeight        for (index in 0..(inputLength - 1)) {

val startX = index * (eachWidth + lineInteval)

val stopX = startX + eachWidth            if (showBottomLine) {                //底部下划线

canvas.drawRect(startX.toFloat(), y, stopX.toFloat(), bottom, linePaint)

}            //获取焦点光标闪动

if (alphaEnable) {                // 当前位置

if (inputCharArray.length == index) {                    if (animEnableShow) {//光标显示

val cursorX = startX + eachWidth / 2f

canvas.drawRect(cursorX

, (measuredHeight - hintBounds.height()) / 2f

, cursorX + cursorWidth

, (measuredHeight + hintBounds.height()) / 2f

, cursorPaint)

}

}

}

}

}    //画提示字

private fun drawHintTxt(canvas: Canvas) {        if (inputCharArray.isEmpty() && !alphaEnable) {

val y: Float = ((measuredHeight + hintBounds.height()) / 2).toFloat() - hintPaint.fontMetrics.bottom / 2

canvas.drawText(hint, 0, hint.length, 0f, y, hintPaint)

}

}

}

在attr.xml中配置 自定义属性

需要的可以增加 属性

使用方式

android:id="@+id/ipv_sms_code"

android:layout_width="0dp"

android:layout_height="50dp"

android:layout_weight="1"

android:paddingBottom="2dp"

app:ipv_bottom_line_color="?attr/gray_1"

app:ipv_bottom_line_height="1dp"

app:ipv_hint_color="?attr/black_gray_1"

app:ipv_hint_text="@string/sms_verify_code"

app:ipv_input_length="6"

app:ipv_input_type="numChar"

app:ipv_show_bottom_line="true"

app:ipv_show_txt_color="?attr/black_1"

app:ipv_txt_size="14sp" />

作者:Mocaris

链接:https://www.jianshu.com/p/b794750c05a1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自定义一个 Dialog,可以按照以下步骤进行操作: 1. 创建一个新的类来扩展 Dialog 类。在这个新类中,你可以定义你自己的布局和逻辑。 2. 在 onCreate() 方法中,加载布局并通过 findViewById() 方法获取视图元素的引用。 3. 在 show() 方法中,设置 Dialog 的大小和样式,然后将布局设置为 Dialog 的内容视图。 4. 在布局中添加必要的视图元素,如 TextView、EditText、Button 等。 5. 在适当的位置为这些视图元素添加响应事件的侦听器。 以下是一个简单的示例代码: ``` class MyDialog(context: Context) : Dialog(context) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.my_dialog_layout) // 获取视图元素 val titleTextView = findViewById<TextView>(R.id.titleTextView) val cancelButton = findViewById<Button>(R.id.cancelButton) // 为按钮添加点击事件侦听器 cancelButton.setOnClickListener { dismiss() } } override fun show() { super.show() // 设置 Dialog 的大小和样式 window?.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT) window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) } } ``` 在这个示例中,我们创建了一个名为 MyDialog 的新类,它扩展了 Dialog 类。在 onCreate() 方法中,我们加载了自定义布局,并使用 findViewById() 方法获取了 TextView 和 Button 的引用。在适当的位置,我们为取消按钮添加了一个点击事件侦听器。在 show() 方法中,我们设置了 Dialog 的大小和样式,并将布局设置为 Dialog 的内容视图。 最后,我们可以在需要的地方创建并显示这个 Dialog: ``` val dialog = MyDialog(context) dialog.show() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值