Android自定义View实现验证码or密码输入框

前言

最近项目中有支付功能,用户输入密码时要类似微信支付密码输入框的样式,本想直接copy网上的,但设计姐姐总是对样式挑三拣四,抽空自己自定义了一个,无奈之下抽空自定义了个,并把它贴到GitHub上供网友们参考。

示例

废话不多说,先看效果图。


number-input-video.gif

实现

BorderTextView

  • 首先,实现这种效果我用多个TextView控件组合,为什么是TextView呢,因为我不仅需要文字大小颜色等可以定制,还要文字的背景色,背景框等可以变化。但系统的TextView设置背景过于单一,假如我要带圆角的背景,甚至是圆角可以变化的背景,这就麻烦了。因此我继承TextView自定义了BorderTextView。

  • BorderTextView控件主要是文字的背景色可变化,有边框和填充两种背景。

  1. 边框的粗细、颜色、圆角均可定制。
  2. 填充背景时,填充颜色,背景圆角可定制。
  3. 除此之外,BorderTextView有明文显示和密文显示两种模式。考虑过设置transformationMethod属性来将TextView显示成"●",但有时候设置的"●"太小了,而且颜色又单一,因此我重写了TextView的setBackgroundColor方法,在文字的中心化了个实心圈覆盖文字,同时"●"的颜色大小均可变化。
  4. 核心代码如下
 override fun onDraw(canvas: Canvas) {
        mStrokePaint.isAntiAlias = true
        mStrokePaint.strokeWidth = strokeWidth.toFloat()
        mStrokePaint.color = strokeColor
        mStrokePaint.style = if (isFill) Paint.Style.FILL else Paint.Style.STROKE
        mStrokePaint.strokeCap = Paint.Cap.ROUND
        //解决canvas.drawRoundRect时,四个圆角线较粗问题
        if (rectF == null) {
            val d = strokeWidth / 2
            rectF = RectF(d.toFloat(), d.toFloat(), (measuredWidth - d).toFloat(), (measuredHeight - d).toFloat())
        }
        if (mBgPaint != null) {
            canvas.drawRoundRect(rectF!!, cornerRadius.toFloat(), cornerRadius.toFloat(), mBgPaint!!)
        }
        canvas.drawRoundRect(rectF!!, cornerRadius.toFloat(), cornerRadius.toFloat(), mStrokePaint)
        if (mIsPassWordMode && text.isNotEmpty()) {
            mDotPaint.style = Paint.Style.FILL
            mDotPaint.color = textColors.defaultColor
            val xy = measuredWidth / 2.toFloat()
            canvas.drawCircle(xy, xy, textSize / 2, mDotPaint)
        }
        super.onDraw(canvas)
    } 
  • EditText
    EditText用于监听用户输入的数字,将其的背景设置成透明,再设置 isCursorVisible = false、inputType = InputType.TYPE_CLASS_NUMBER 属性。同时,用户输入的时候需要拦截输入内容,再将内容显示到BorderTextView上。监听用户键盘的KeyEvent.KEYCODE_DEL事件用户处理输入内容的删除
  • 搞定BorderTextView和EditText后就简单了,用List集合存储TextViews,创建LineaLayout将N个TextView添加过去,调整其位置就ok了。
   /**
    * 初始化EditText
    */
    private fun initEditText() {
        mEditText = EditText(context)
        mEditText.let {
            it.setBackgroundColor(Color.TRANSPARENT)
            it.isFocusable = true
            it.isCursorVisible = false
            it.inputType = InputType.TYPE_CLASS_NUMBER
        }
    }
  /**
  * 监听删除键
  **/
  mEditText.setOnKeyListener { v, keyCode, event ->
            if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN) {
                if (mInputSb.isNotEmpty()) {
                    mInputSb.delete(mInputSb.length - 1, mInputSb.length)
                    mTextViews[mInputSb.length].text = ""
                    return@setOnKeyListener true
                }
            }
            return@setOnKeyListener false
        }

自定义属性

name 说明 format 默认值
niv_text_size_sp 输入框字体大小 integer 16
niv_text_color 输入框字体颜色 color #333333
niv_text_divider 输入框间隔 dimension 5
niv_text_width 输入框宽度(width=height) dimension 40
niv_border_width 输入框边框宽度 dimension 2
niv_border_color 输入边框颜色 color #333333
niv_border_radius 输入框圆角角度 dimension 4
niv_is_fill 是否填充输入框 boolean false
niv_count 输入框个数(最大为10) integer 6
niv_is_pw_mode 输入数字是否用点代替 boolean false

可用方法

method_name description return type
setInputCompleteListener(inputCompleteListener: InputCompleteListener) 输入完成时监听 Unit

使用示例

  • 上示例图中xml代码如下

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        android:paddingBottom="20dp"
        android:paddingTop="20dp"
        tools:context="com.neworin.sample.MainActivity">
    
        <com.neworin.numberinputview.widget.NumberInputView
            android:id="@+id/sample_niv1"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:niv_count="4"
            app:niv_is_fill="false"
            app:niv_text_size_sp="18"/>
    
        <com.neworin.numberinputview.widget.NumberInputView
            android:id="@+id/sample_niv2"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:niv_border_color="@color/colorPrimaryDark"
            app:niv_border_radius="0dp"
            app:niv_count="5"
            app:niv_text_color="@color/color_red"/>
    
        <com.neworin.numberinputview.widget.NumberInputView
            android:id="@+id/sample_niv3"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:niv_border_color="@color/input_layout_bg"
            app:niv_border_radius="0dp"
            app:niv_count="6"
            app:niv_is_fill="true"
            app:niv_text_size_sp="20"/>
    
        <com.neworin.numberinputview.widget.NumberInputView
            android:id="@+id/sample_niv4"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:niv_count="6"
            app:niv_is_pw_mode="true"
            app:niv_text_color="@color/colorPrimary"
            app:niv_text_size_sp="18"/>
    
    </LinearLayout>
    

效果图

最后附上多种效果图以及GitHub地址:https://github.com/NewOrin/number-input

效果图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容