验证码自定义控件

效果图

在这里插入图片描述
自定义边框
在这里插入图片描述
内部控制倒计时
在这里插入图片描述
居中/宽度自适应
在这里插入图片描述

控件源代码


class VerificationCodeView : View {
    val mContext: Context
    var enableStr: String
    var disableStr: String
    var totalCountdownTime: Int
    var mTickCount: Long = 0
    var enablColor: Int
    var disablColor: Int
    var boardColor: Int
    var showBoardColor = false
    var mEnable = true
    var textsize: Float = 0F
    var padding: Float = 0F
    var strokeWidth: Float = 0F
    var radiusSize: Float = 0F

    var fatherHeight: Float = 0F
    var fatherWidth: Float = 0F

    lateinit var fatherRectF: RectF
    lateinit var textPaint: TextPaint
    lateinit var boardPaint: Paint

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

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    ) {
        mContext = context
        val a = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView)
        totalCountdownTime = a.getInteger(R.styleable.VerificationCodeView_totalCountdownTime, 60)
        textsize = a.getDimension(R.styleable.VerificationCodeView_codeTextSize, dp2px(14f))
        showBoardColor = a.getBoolean(R.styleable.VerificationCodeView_showBoardColor, false)
        mEnable = a.getBoolean(R.styleable.VerificationCodeView_enable, true)
        enableStr = a.getString(R.styleable.VerificationCodeView_enableStr) ?: mContext.getString(
            com.guide.strings.R.string.userinfo_get_code
        )
        disableStr = a.getString(R.styleable.VerificationCodeView_disableStr) ?: "%dS"
        enablColor = a.getColor(
            R.styleable.VerificationCodeView_enableColor, ContextCompat.getColor(
                mContext, color.lib_common_selected
            )
        )
        disablColor = a.getColor(
            R.styleable.VerificationCodeView_disableColor, ContextCompat.getColor(
                mContext, color.lib_common_color_dd
            )
        )

        boardColor = a.getColor(
            R.styleable.VerificationCodeView_boardColor, ContextCompat.getColor(
                mContext, color.lib_common_selected
            )
        )
        a.recycle()
        init()
    }


    private fun init() {
        setWillNotDraw(false)
        padding = dp2px(40F)
        strokeWidth = dp2px(1F)
        radiusSize = dp2px(3F)
        initPaint()
    }

    private fun initPaint() {
        textPaint = TextPaint()
        textPaint.color = enablColor
        textPaint.textSize = textsize
        textPaint.style = Paint.Style.FILL

        boardPaint = Paint()
        boardPaint.color = boardColor
        boardPaint.isAntiAlias = true
        boardPaint.style = Paint.Style.STROKE
        boardPaint.strokeWidth = strokeWidth


        fatherWidth = getTextW(textPaint, enableStr) + padding
        fatherHeight = getTextH(textPaint, enableStr) + padding / 2
    }

    /**
     * 开启倒计时
     */
    fun startCountdown() {
        mViewCountDownTimer?.cancel()
        mViewCountDownTimer = ViewCountDownTimer(totalCountdownTime * 1000L, 1000L)
        mViewCountDownTimer?.start()
    }

    fun cancelCountdown() {
        mViewCountDownTimer?.cancel()
        mViewCountDownTimer = null
    }

    override fun onDetachedFromWindow() {
        cancelCountdown()
        super.onDetachedFromWindow()
    }

    var mViewCountDownTimer: ViewCountDownTimer? = null

    inner class ViewCountDownTimer(millisInFuture: Long, countDownInterval: Long) :
        CountDownTimer(millisInFuture, countDownInterval) {

        override fun onTick(p0: Long) {
            mTickCount = p0 / 1000
            mEnable = false
            postInvalidate()
        }

        override fun onFinish() {
            mEnable = true
            postInvalidate()
        }

    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (mEnable) {
            if (isTouch) {
                textPaint.color = disablColor
                boardPaint.color = disablColor
            } else {
                textPaint.color = enablColor
                boardPaint.color = enablColor
            }
            if (showBoardColor) {
                canvas?.drawRoundRect(fatherRectF, radiusSize, radiusSize, boardPaint)
            }
            canvas?.drawText(
                enableStr,
                (fatherWidth - getTextW(textPaint, enableStr)) / 2,
                (getTextH(textPaint, enableStr) + fatherHeight) / 2,
                textPaint
            )
        } else {
            textPaint.color = disablColor
            boardPaint.color = disablColor
            if (showBoardColor) {
                canvas?.drawRoundRect(fatherRectF, radiusSize, radiusSize, boardPaint)
            }
            val format = String.format(disableStr, mTickCount)
            canvas?.drawText(
                format,
                (fatherWidth - getTextW(textPaint, format)) / 2,
                (getTextH(textPaint, format) + fatherHeight) / 2,
                textPaint
            )
        }
    }

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

        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)


        //不能超过父布局大小
        if (fatherWidth > widthSize) {
            fatherWidth = widthSize.toFloat()
        }

        fatherRectF = RectF(0F, 0F, fatherWidth, fatherHeight)

        Log.d("ssss", "widthMode " + widthMode)
        Log.d("ssss", "widthSize " + widthSize)
        Log.d("ssss", "heightSize " + heightSize)

        setMeasuredDimension(fatherWidth.toInt(), fatherHeight.toInt())
    }

    private fun dp2px(dpValue: Float): Float {
        val scale = Resources.getSystem().displayMetrics.density
        return dpValue * scale + 0.5f
    }

    private fun getTextH(pFont: TextPaint, text: String): Int {
        val rect = Rect()
        pFont.getTextBounds(text, 0, text.length, rect)
        return rect.height()
    }

    private fun getTextW(pFont: TextPaint, text: String): Float {
        return pFont.measureText(text)
    }

    var isTouch = false
    var lastAction: Int = -1
    var actionDownTime: Long = 0
    var actionUpTime: Long = 0L
    var clickSpaceTime: Long = 1000L
    var lastClickTime: Long = 0L

    public interface OnClickListener {
        fun onClick()
    }

    var mOnClickListener: OnClickListener? = null

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (MotionEvent.ACTION_DOWN == event.action) {
            actionDownTime = System.currentTimeMillis()
            lastAction = MotionEvent.ACTION_DOWN
            isTouch = true
            invalidate()
        } else if (MotionEvent.ACTION_MOVE == event.action) {
            lastAction = MotionEvent.ACTION_MOVE
            isTouch = true
            invalidate()
        } else if (MotionEvent.ACTION_UP == event.action) {
            lastAction = MotionEvent.ACTION_UP
            actionUpTime = System.currentTimeMillis()
            val canClickSpace = actionUpTime - lastClickTime > clickSpaceTime
            val isClick = actionUpTime - actionDownTime < clickSpaceTime
            if (mEnable && canClickSpace && isClick) {
                lastClickTime = actionUpTime
                mOnClickListener?.onClick()
            }
            isTouch = false
            invalidate()
        }
        return true
    }
}

Style

 <declare-styleable name="VerificationCodeView">
        <attr name="enable" format="boolean" />
        <attr name="showBoardColor" format="boolean" />
        <attr name="disableColor" format="color|reference" />
        <attr name="enableColor" format="color|reference" />
        <attr name="backColor" format="color|reference" />
        <attr name="boardColor" format="color|reference" />
        <attr name="totalCountdownTime" format="integer" />
        <attr name="enableStr" format="reference" />
        <attr name="disableStr" format="reference" />
        <attr name="codeTextSize" format="reference" />
    </declare-styleable>
id功能
enable可用标志
showBoardColor是否展示边框
disableColor不可用颜色
enableColor可用颜色
backColor背景色
boardColor边框颜色
totalCountdownTime倒计时总时长
enableStr可用字符串
disableStr不可用字符串
codeTextSize文字大小

Xml

    <com.guide.userinfo.widget.VerificationCodeView
        android:id="@+id/tv_get_code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="@dimen/lib_common_20dp"
        app:codeTextSize="@dimen/lib_common_12sp"
        app:disableColor="@color/lib_common_gray_999"
        app:disableStr="@string/userinfo_num"
        app:enable="true"
        app:enableStr="@string/userinfo_get_code"
        app:layout_constraintBottom_toBottomOf="@+id/mobile_code"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@+id/mobile_code"
        app:showBoardColor="false"
        app:totalCountdownTime="60" />

Code

手动开启倒计时

     mViewBinding.tvGetCode.mOnClickListener = object : VerificationCodeView.OnClickListener {
            override fun onClick() {
                //发送验证码成功
                mViewBinding.tvGetCode.startCountdown()
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
功能介绍:  为网页编程人员提供能够自动生成验证码图像并验证网页访问者输入的Web件,具体功能如下:1. 提供简单易用的设计时所见即所得的可视化设置方式,并且支持设计时验证码图像效果与特效属性设置的实时联动体现,极大地提高程序员的工作效率;2. 对验证码图像的包括残影、打散、风化、旋转、斜变等多种图形学图像处理特效以及对各种特效的三个程度等级的灵活制能力,让程序员在轻松应对基于OCR的恶意识别攻击的情况下,还能有充分的余地考虑验证码图像外观的美化问题;3. 提供灵活的中文诗词、中文单字、英文大小写字母、阿拉伯数字等丰富的验证码生成字源混合制以及对于字数和字体的自定义制,让程序员在面对不同客户以及网页访问者的特殊要求的同时仍能从容兼顾良好的用户体验;4. 保留对抗OCR的经典的点、线干扰特效以及三个程度等级的灵活制,并采用色调匹配技术在保证原有的OCR对抗效果的同时加入了更加美观的彩色点、线效果,留给程序员更多的选择;5. 无刷新页面验证。更好地适用于需要填写大量信息的页面验证,有效地避免由于因突发性网络原因导致的验证码图像的无法下载,而使网页用户必须刷新页面而重填其它信息的窘境。运行环境:1. Microsoft Windows XP Professional2. Microsoft Visual Studio 20053. Microsoft .NET Framework V2.04. Microsoft Internet Information Services (IIS) V5.1(注意在子安装选项中选中FrontPage 2000服务器扩展)常见问答:1. 如何将本件添加到Microsoft Visual Studio 2005的IDE中?a) 在Microsoft Visual Studio 2005中打开源代码的工程文件,重新编译,生成vcg.dll;b) 在工具箱(Toolbox)面板上单击右键,选择Choose Items…菜单,在弹出来的Choose ToolBox Items属性面板中,点击Browse…找到并选定vcg.dll件。该件即被添加到工具箱;2. 如何使用本件?a) 确认需要添加本件的网页为aspx页面。在IIS管理器中将网站属性的ASP.NET version选中为2.0,并在网站虚拟目录属性的“安全”选项卡中添加ASP.NET用户,赋予写入权限;b) 在Microsoft Visual Studio 2005中打开相应的网站,并打开相应的aspx页面文件(在本文中以Default.aspx为例),进入Design编辑模式;c) 从工具箱将之前添加的vcg件拖到Default.aspx页面上。此时页面上的拖放位置应该出现一个带有文字内容的图片框,说明vcg件已经被正确添加到页面;d) 现在可以像修改其它标准件一样通过鼠标对件进行拖动、缩放等修改,还可以在属性栏对件进行进一步的细节设置。主要包括针对验证码图像的特效制和针对验证码本身的文字制两个方面。具体内容请参考本件的使用手册;e) 在Default.aspx中新增Web件Button:btnValidate,作为验证促发;在Default.aspx中新增Web件TextBox:textCode,作为验证码输入;在Default.aspx中新增Web件Lable:lblMessage,作为验证结果输出;f) 在Default.aspx.cs中添加验证函数:protected void btnValidate_Click(object sender, EventArgs e){ string code = “”; try { //真正的验证码存储在Session[“Code”]中,需要的只是对验证码输入和该值进行比较。 //(如果属性栏中“文字制”属性卡下的“SessionCode”默认属性值“Code”改变, //则在代码中的Session[”Code”]中引号内的值也必须手工修改成与属性值一致的字符串。) code = Session[”Code”].ToString(); } catch (Exception ex

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值