文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android怎么实现自定义密码输入框

2023-06-25 13:45

关注

本篇内容主要讲解“Android怎么实现自定义密码输入框”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android怎么实现自定义密码输入框”吧!

一、实现效果及方案

预期效果图:

Android怎么实现自定义密码输入框

如上图所示,要实现一个这种密码输入框的样式,原生并未提供类似的效果,所以需要自定义控件的方式实现。

预期的基础效果:

只接受数字;

支持输入加密显示;

支持删除;

密码位数可配置;

文字大小、颜色、数字框背景可配置;

方案分析:

需要解决的问题:

配置性;

输入、删除如何实现?

整体UI如何实现?

对于输入删除可以通过setOnKeyListener监听软件盘的事件。

可配置性数据可以通过自定义的属性文件配置;

对于UI效果:

A:可以基于原生控件做开发,每一个数字布局对应一个TextView,选用数据结构对其管理,再选用一种容器布局,比如LinearLayout进行添加。

B:通过自定义View的方式开发,需要自行绘制,绘制的内容包括背景、及密码内容、密码加密样式内容。

二、实现

这里选用方案B的方式进行实现,尽量使用较少的控件去实现,使用A的方案至少要用到5个原生控件的组合。

继承ViewGrop还是View?

如果选用方案A的话其实算是继承了ViewGrop,而内部的单个数字则作为一个独立的子控件,这样的话是可以继承ViewGrop的
,但显然不需要这么麻烦(需要处理layout等),这个密码输入就是一个独立的控件不需要再加入子控件,所以直接继承View。

class PasswordEditText @JvmOverloads constructor(    context: Context,    attributeSet: AttributeSet? = null,) : View(context, attributeSet, 0) {    }

继承View的话就要处理 wrap_content,所以要重写onMeasure,即在未设置具体的宽度时也要能够正常的显示测量。先定义一些宽高颜色的变量:

 //密码位数    private var passwordLength = 4    private var textColor = 0    //间隔  ->   dp2px    private var itemPadding = 5    //单个数字包括背景宽度 dp2px    private var itemWidth = 30    private var bgItemColor = 0    private val mPaintBg = Paint()    //用于存储输入后的密码    private val password = arrayOfNulls<String>(passwordLength)

宽度的话相对来说还是很好计算的:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec)        var width = 0        when (MeasureSpec.getMode(widthMeasureSpec)) {            MeasureSpec.UNSPECIFIED,MeasureSpec.AT_MOST ->{                width = itemWidth * passwordLength + itemPadding * (passwordLength-1)            }            MeasureSpec.EXACTLY ->{                width = MeasureSpec.getSize(widthMeasureSpec)                itemWidth = (width - itemPadding *(passwordLength -1)) / passwordLength            }        }        setMeasuredDimension(width,itemWidth)    }

看着UI图基本可以算出来了,不涉及太复杂的计算,这里并未对高度进行处理,理论上高度的值应该用指定的就好了;
需要做的测量基本就是这些了,下面开始绘制背景了:

也很简单根据 passwordLength 循环绘制圆角矩形就OK了,而参数的话也很好计算出来:

private fun drawBgItems(canvas: Canvas) {        for (i in password.indices) {            未处理padding值 加上即可            val rect = RectF(                (i * itemWidth + (i) * itemPadding).toFloat(),                0f,                ((i+1) * itemWidth + i * itemPadding).toFloat(),                itemWidth.toFloat()            )            canvas.drawRoundRect(rect, 5f, 5f, mPaintBg)        }    }

为了让效果更明显,先画了一个颜色鲜艳的:

Android怎么实现自定义密码输入框

背景的话就绘制OK了,下面要做的就是监听事件再绘制密码内容了;

要实现一个OnKeyListener

 //键盘监听    private val keyListener = OnKeyListener { v, keyCode, event ->        val action = event.action        if (action == KeyEvent.ACTION_DOWN) {            if (keyCode == KeyEvent.KEYCODE_DEL) {                //删除                return@OnKeyListener true            }            if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {                 //数字键            }            if (keyCode == KeyEvent.KEYCODE_ENTER) {                //确认键                return@OnKeyListener true            }        }        return@OnKeyListener false    }

这里只是添加好了回调条件,还要做相应的处理。但键盘还没弹出,所以要先处理点击事件调用系统的方法主动弹出软键盘才行

 override fun onTouchEvent(event: MotionEvent?): Boolean {        if (event!!.action == MotionEvent.ACTION_DOWN) {            //获取焦点            requestFocus()            //getContext().getSystemService(Context.INPUT_METHOD_SERVICE)            inputManager.showSoftInput(this, InputMethodManager.SHOW_FORCED)            return true        }        return super.onTouchEvent(event)    }

重写onTouchEvent之后就可以拦截点击事件弹出键盘拉。而View和软键盘的联系需要通过onCreateInputConnection 来实现,具体可以看下源码的介绍。

下面接着处理监听事件,首先是在接受到数字输入时的处理,要把输入的数字存储到容器并绘制出来

这里需要注意keyCode 的值,看下源码并不是KEYCODE_0 就是0了

Android怎么实现自定义密码输入框

再存储一下输入的数字:

 if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {                 //数字键                password[currentInputPosition] = (keyCode - 7).toString()                currentInputPosition++                postInvalidate()                return@OnKeyListener true            }

currentInputPosition为了标记当前操作的位置,方便添加和删除,因为都是从两头开始的用这个值就可以了。

下面开始绘制文字了,如果加密的话只需要在每个背景的中心画一个小黑点就OK了,或者直接画一个数字,根据基线用drawText画就好了,而Y轴的基线很好确定就是高度的一半像素减去高度文字一半,通过设置textAlign = Paint.Align.CENTER即可实现横向上的居中(会根据X基线),X轴的基线则需要计算一下,比如第一个框的X基线则应该是,框宽的一半再减去绘制文字宽度的一半,这样才能在中间,第二个框内X的基线应该是:paddingLeft+1框宽+1padding+框宽/2

所以绘制文字的代码就出来了:

 //绘制文字    private fun drawPasswordNumber(canvas: Canvas) {        for (i in password.indices) {            if (password[i] != null) {                //没有开启明文显示,绘制密码密文                val txt = if (isCipherEnable) cipherString else password[i]                mPaintTv.getTextBounds(txt, 0, txt!!.length, rectTv)                val offset = (rectTv.top + rectTv.bottom) / 2                canvas.drawText(                    password[i]!!,                    (paddingLeft + itemWidth * i + itemPadding * i + itemWidth / 2).toFloat(),                    (paddingTop + itemWidth / 2).toFloat() - offset, mPaintTv                )            }        }    }

这里加了是否开启密文显示的开关,最终运行的效果如下:

Android怎么实现自定义密码输入框
Android怎么实现自定义密码输入框

这个黑点也可以通过画圆的方式进行绘制,但无法通过字符串进行动态配置。

再输入完四位以后在点的话就会数组越界闪退了,所以在完成相应位数的添加后要禁止再绘制。

if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {                //加入判断 currentInputPosition                 if (currentInputPosition == passwordLength) {                    return@OnKeyListener true                }                password[currentInputPosition] = (keyCode - 7).toString()                currentInputPosition++                postInvalidate()                return@OnKeyListener true            }

下面要处理删除操作了,删除要做的就是去除数组中保存的已输入密码,更新操作标记位,再刷新绘制就OK了

if (keyCode == KeyEvent.KEYCODE_DEL) {                //删除                if(currentInputPosition == 0){                    return@OnKeyListener true                }                password[currentInputPosition-1] = null                currentInputPosition--                postInvalidate()                return@OnKeyListener true            }

看下最后的UI效果:

Android怎么实现自定义密码输入框

下面可以提供一些对外的方法、接口,比如获取内容,输入删除确认的回调监听。

//获取输入内容    fun getTextContent():String {        val sb = StringBuilder()        for (p in password) {            p?.let {                sb.append(p)            }        }        return sb.toString()    }    //操作回调 加些需要的参数    interface OperationListener{        fun inputOperationCallBack()                fun completeOperationCallBack()                fun deleteOperationCallBack()    }

这里还可以继续开发其他一些主流的样式,比如下划线、网格的样式,但绘制思路基本相同,还可以加上一个任务类执行绘制光标的操作。

到此,相信大家对“Android怎么实现自定义密码输入框”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯