欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现自定义验证码输入框效果(实例代码)

程序员文章站 2022-03-04 17:05:15
这里提一下,这个当时也是在网上看到一个博主写的代码改了下用在我么项目中的验证码输入框。博主的地址不记得了这里只能顺带标注一下。。。 效果图如下: 就是这个酱紫 直入主题,代码...

这里提一下,这个当时也是在网上看到一个博主写的代码改了下用在我么项目中的验证码输入框。博主的地址不记得了这里只能顺带标注一下。。。

效果图如下:

Android实现自定义验证码输入框效果(实例代码)

就是这个酱紫

直入主题,代码如下:

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:gravity="end"
  >
 <textview
   android:id="@+id/tv_view_top_tip"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_marginbottom="5dp"
   android:textcolor="@color/img_code_text_error_color"
   android:textsize="12sp"
   android:text="error"
   />
 <relativelayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">
  <linearlayout
    android:id="@+id/ll_code"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:baselinealigned="false">
   <linearlayout
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginright="5dp">
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code1"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:textsize="24sp"
       android:textstyle="bold"
       android:background="@null"
       android:layout_centerinparent="true"
       android:gravity="center"/>
     <view
       android:id="@+id/v1_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor"
       />
    </relativelayout>
 
    <view
      android:id="@+id/v1"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/maincolor" />
   </linearlayout>
 
   <linearlayout
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginright="5dp"
     android:layout_marginleft="5dp">
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code2"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:textsize="24sp"
       android:textstyle="bold"
       android:background="@null"
       android:layout_centerinparent="true"
       android:gravity="center"/>
     <view
       android:id="@+id/v2_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor" />
    </relativelayout>
 
    <view
      android:id="@+id/v2"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/global_text_color_grey" />
   </linearlayout>
   <linearlayout
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginright="5dp"
     android:layout_marginleft="5dp">
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code3"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:textsize="24sp"
       android:textstyle="bold"
       android:background="@null"
       android:layout_centerinparent="true"
       android:gravity="center"/>
     <view
       android:id="@+id/v3_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor"/>
    </relativelayout>
 
    <view
      android:id="@+id/v3"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/global_text_color_grey" />
   </linearlayout>
   <linearlayout
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginright="5dp"
     android:layout_marginleft="5dp">
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code4"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:background="@null"
       android:textstyle="bold"
       android:textsize="24sp"
       android:layout_centerinparent="true"
       android:gravity="center"/>
 
     <view
       android:id="@+id/v4_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor" />
    </relativelayout>
    <view
      android:id="@+id/v4"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/global_text_color_grey" />
   </linearlayout>
   <linearlayout
     android:id="@+id/ll5_parent"
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginright="5dp"
     android:layout_marginleft="5dp">
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code5"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:background="@null"
       android:textstyle="bold"
       android:textsize="24sp"
       android:layout_centerinparent="true"
       android:gravity="center"/>
 
     <view
       android:id="@+id/v5_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor" />
    </relativelayout>
    <view
      android:id="@+id/v5"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/global_text_color_grey" />
   </linearlayout>
   <linearlayout
     android:id="@+id/ll6_parent"
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:orientation="vertical"
     android:layout_marginleft="5dp">
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginbottom="6dp"
    >
     <textview
       android:id="@+id/tv_code6"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textcolor="@color/global_text_color_10"
       android:background="@null"
       android:textstyle="bold"
       android:textsize="24sp"
       android:layout_centerinparent="true"
       android:gravity="center"/>
 
     <view
       android:id="@+id/v6_center_line"
       android:layout_width="1.5dp"
       android:layout_height="16dp"
       android:visibility="invisible"
       android:layout_centerinparent="true"
       android:background="@color/maincolor" />
    </relativelayout>
    <view
      android:id="@+id/v6"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="@color/global_text_color_grey" />
   </linearlayout>
  </linearlayout>
 
  <edittext
    android:id="@+id/et_code"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_aligntop="@+id/ll_code"
    android:layout_alignbottom="@+id/ll_code"
    android:background="@android:color/transparent"
    android:textcolor="@android:color/transparent"
    android:cursorvisible="false"
    android:inputtype="number"/>
 </relativelayout>
 
 <textview
   android:id="@+id/tv_get_sms_code"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_margintop="9.5dp"
   android:paddingbottom="10dp"
   android:textcolor="@color/text_color_pressed_selector"
   android:textsize="12sp"
   android:text="@string/resend_verify_code"
 />
 
</linearlayout>
class customsmscodeinputlayout : relativelayout, view.onclicklistener {
 
 /**
  * 枚举中有两种状态,four四个输入框,six6个输入框
  */
 enum class inputlinenum(var num: int){
  four(4), six(6)
 }
 
 override fun onclick(v: view?) {
  when(v?.id){
   r.id.tv_get_sms_code->{
    clearallinputvalues()
    if (onclicksmscodetvlistener != null) {
     onclicksmscodetvlistener?.onclick(tv_get_sms_code)
    }
   }
  }
 }
 
 /*启动计时器*/
 fun startcountdowntimer() {
  cancelcountdowntimer()
  /*倒计时60秒,每次执行间隔1秒*/
  mcountdowntimerutil = countdowntimerutil(mcontext, tv_get_sms_code, 60000, 1000)
  mcountdowntimerutil?.start()
 }
 
 /*上下文*/
 private var mcontext: context
 /*存放验证码集合*/
 var codes: arraylist<string>? = arraylist()
 /*输入相关管理器*/
 private var imm: inputmethodmanager? = null
 
 private var color_default = color.parsecolor("#999999")
 private var color_focus = color.parsecolor("#ff9200")
 private var color_centerline = color.parsecolor("#ff9200")
 
 /*是否显示中间竖线*/
 private var isvisiblecenterline = true
 
 private var defaultinputnum = inputlinenum.six
 
 private var mcountdowntimerutil: countdowntimerutil? = null
 
 constructor(context: context) : super(context){
  mcontext = context
  initview()
 }
 
 constructor(context: context, attrs: attributeset) : super(context, attrs){
  mcontext = context
  initview()
 }
 
 private fun initview() {
  imm = mcontext.getsystemservice(context.input_method_service) as inputmethodmanager?
  layoutinflater.from(mcontext).inflate(r.layout.view_sms_code_input_layout, this)
  initevent()
 }
 
 private fun initevent() {
  //验证码输入
  et_code.addtextchangedlistener(object : textwatcher {
   override fun beforetextchanged(charsequence: charsequence, i: int, i1: int, i2: int) {}
   override fun ontextchanged(charsequence: charsequence, i: int, i1: int, i2: int) {}
   override fun aftertextchanged(editable: editable?) {
    if (editable != null && editable.trim().isnotempty()) {
     // 每输入
     et_code.settext("")
     when(defaultinputnum){
      inputlinenum.four -> {
       regexmaxinputsize(editable, inputlinenum.four.num)
      }
      inputlinenum.six -> {
       regexmaxinputsize(editable, inputlinenum.six.num)
      }
     }
 
    }
   }
  })
  // 监听验证码删除按键
  et_code.setonkeylistener(object : view.onkeylistener {
   override fun onkey(view: view, keycode: int, keyevent: keyevent): boolean {
    if (keycode == keyevent.keycode_del && keyevent.action == keyevent.action_down && codes?.size!! > 0) {
     codes!!.removeat(codes?.size!! - 1)
     //回退的时候如果顶部的提示语显示则隐藏掉
     if (tv_view_top_tip.visibility == view.visible){
      tv_view_top_tip.visibility = view.invisible
     }
     showcode()
     return true
    }
    return false
   }
  })
  tv_get_sms_code.setonclicklistener(this)
 }
 
 /*控制可输入的最大长度*/
 private fun regexmaxinputsize(editable: editable, maxsize: int) {
  if (codes?.size!! < maxsize) {
   // 过滤掉由空格键引起的字符串出现空长串的问题,使用正则替换规则(\\s*)可以替换掉绝大多数空白字符或空格
   codes?.add(editable.tostring().replace(regex("\\s*"), ""))
   showcode()
  }
 }
 
 /**
  * 显示输入的验证码
  */
 private fun showcode() {
  var code1: string? = ""
  var code2: string? = ""
  var code3: string? = ""
  var code4: string? = ""
  var code5: string? = ""
  var code6: string? = ""
  if (codes?.size!! >= 1) {
   code1 = codes?.get(0)
  }
  if (codes?.size!! >= 2) {
   code2 = codes?.get(1)
  }
  if (codes?.size!! >= 3) {
   code3 = codes?.get(2)
  }
  if (codes?.size!! >= 4) {
   code4 = codes?.get(3)
  }
  if (codes?.size!! >= 5) {
   code5 = codes?.get(4)
  }
  if (codes?.size!! >= 6) {
   code6 = codes?.get(5)
  }
  tv_code1.text = code1
  tv_code2.text = code2
  tv_code3.text = code3
  tv_code4.text = code4
  tv_code5.text = code5
  tv_code6.text = code6
 
  setcolor()//设置高亮颜色
  callback()//回调
 }
 
 /**
  * 设置高亮颜色
  */
 private fun setcolor() {
  v1.setbackgroundcolor(color_default)
  v2.setbackgroundcolor(color_default)
  v3.setbackgroundcolor(color_default)
  v4.setbackgroundcolor(color_default)
  v5.setbackgroundcolor(color_default)
  v6.setbackgroundcolor(color_default)
  if (codes?.size == 0) {
   v1.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v1_center_line)
  }
  if (codes?.size == 1) {
   v2.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v2_center_line)
  }
  if (codes?.size == 2) {
   v3.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v3_center_line)
  }
  if (codes?.size!! == 3) {
   v4.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v4_center_line)
  }
  if (codes?.size == 4) {
   v5.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v5_center_line)
  }
  if (codes?.size!! == 5) {
   v6.setbackgroundcolor(color_focus)
   updatecenterlinecolor(v6_center_line)
  }
  if ((defaultinputnum == inputlinenum.four && codes?.size!! >= 4)
   || (defaultinputnum == inputlinenum.six && codes?.size!! >= 6)) {
   invisibleallcenterline()
  }
 }
 
 /**
  * 回调
  */
 private fun callback() {
  if (oninputlistener == null) {
   return
  }
  if ((defaultinputnum == inputlinenum.four && codes?.size == 4)
   ||(defaultinputnum == inputlinenum.six && codes?.size == 6)) {
   /*zi自动收起软键盘*/
   dismisssoftinput()
   oninputlistener!!.onsuccess(getphonecode())
  } else {
   oninputlistener!!.oninput()
  }
 }
 
 //定义回调
 interface oninputlistener {
  fun onsuccess(code: string)
  fun oninput()
 }
 
 /**
  * 显示键盘
  */
 fun showsoftinput() {
  //显示软键盘
  if (imm != null && et_code != null) {
   et_code.requestfocus() //需先获得焦点才能主动弹出软键盘
   et_code.postdelayed({ imm?.showsoftinput(et_code, inputmethodmanager.show_forced) }, 200)
  }
 }
 
 /**
  * 英藏键盘
  */
 fun dismisssoftinput() {
  et_code.requestfocus()
  //某些情况下必须延迟一定时间在执行,不然英藏不了
  et_code.postdelayed({ imm?.hidesoftinputfromwindow(et_code.windowtoken, 0) }, 200) //强制隐藏键盘
 }
 
 /**
  * 获得手机号验证码
  * @return 验证码
  */
 fun getphonecode(): string {
  val sb = stringbuilder()
  return if (!codes!!.isempty()) {
   for (code in codes!!) {
    sb.append(code)
   }
   sb.tostring()
  }else{
   ""
  }
 }
 
 /*更新竖线显示以及颜色*/
 private fun updatecenterlinecolor(view: view){
  if (isvisiblecenterline) {
   invisibleallcenterline()
   view.visibility = view.visible
  }
 }
 
 /*英藏所有竖线*/
 private fun invisibleallcenterline() {
  v1_center_line.visibility = view.invisible
  v2_center_line.visibility = view.invisible
  v3_center_line.visibility = view.invisible
  v4_center_line.visibility = view.invisible
  v5_center_line.visibility = view.invisible
  v6_center_line.visibility = view.invisible
 }
 
 /*设置顶部提示是否显示*/
 fun settoptipvisible(isvisible: boolean){
  tv_view_top_tip.visibility = if(isvisible) view.visible else view.invisible
 }
 
 /*设置当前项中间竖线是否显示*/
 fun setcurrentcenterlinevisible(isvisible: boolean){
  isvisiblecenterline = isvisible
  //显示竖线的话默认显示出第一条
  v1_center_line.visibility = if(isvisiblecenterline) view.visible else view.invisible
 }
 
 /*设置底部获取短信按钮是否显示*/
 fun setbottomsmstvvisible(isvisible: boolean){
  tv_get_sms_code.visibility = if(isvisible) view.visible else view.gone
 }
 
 /*设置顶部提示字样*/
 fun settoptiptext(text: string){
  tv_view_top_tip.text = text
 }
 
 /*设置顶部提示字样颜色*/
 fun settoptiptextcolor(textcolor: int){
  tv_view_top_tip.settextcolor(textcolor)
 }
 
 /*设置当前指定项下环线颜色*/
 fun setcurrentindexlinecolor(underlinecolor: int){
  color_focus = underlinecolor
  v1.setbackgroundcolor(color_focus)
 }
 
 /*设置当前指定项的中间线颜色*/
 fun setcenterlinecolor(centerlinecolor: int){
  color_centerline = centerlinecolor
  v1_center_line.setbackgroundcolor(color_centerline)
 }
 
 /*设置不是当前指定项下划线颜色*/
 fun setanotherindexlinecolor(underlinecolor: int){
  color_default = underlinecolor
 }
 
 /*设置顶部提示的字样和颜色*/
 fun settoptextandcolor(text: string, textcolor: int){
  tv_view_top_tip.text = text
  tv_view_top_tip.settextcolor(textcolor)
 }
 
 /*允许的输入类型*/
 fun setinputtype(type: int) {
  et_code?.inputtype = type
 }
 
 /*更新获取短信按钮状态*/
 fun updategetsmstvenable(isenable: boolean){
  tv_get_sms_code.isenabled = isenable
  tv_get_sms_code.settextcolor(mcontext.resources.getcolor(r.color.global_text_color_6c))
 }
 
 /*需要展示的输入框数量*/
 fun setshowinputnum(num: inputlinenum){
  defaultinputnum = num
  when(defaultinputnum){
   inputlinenum.four -> {
    ll5_parent.visibility = view.gone
    ll6_parent.visibility = view.gone
   }
   inputlinenum.six -> {
    ll5_parent.visibility = view.visible
    ll6_parent.visibility = view.visible
   }
  }
 }
 
 /*关闭清除计时器*/
 fun cancelcountdowntimer(){
  if (mcountdowntimerutil != null){
   mcountdowntimerutil?.cancel()
   mcountdowntimerutil = null
  }
 }
 
 /**清除所有输入的值*/
 fun clearallinputvalues(){
  settoptipvisible(false)
  codes?.clear()
  showcode()
 }
 
 /**
  * 获取到验证码进行弹窗显示
  */
 fun showsmscodedialogtip(msg: string, title: string){
  val msgsplit = msg.tolist()
  dialogcreator.createtitledialog(
   mcontext as activity,
   title,
   msg,
   dialogviewinfo("知道了"){ _,_ ->
    codes?.clear()
    msgsplit.foreach { item -> codes?.add(item.tostring()) }
    showcode()
   }
  ).subscribe()
 }
 
 /**
  * 验证出错时抖动输入框提示
  */
 fun startshaketip(){
  val animx = objectanimator.offloat(this, "translationx", 0f, 5f, -10f, 0f)
  val animy = objectanimator.offloat(this, "translationy", 0f, 5f, -10f, 0f)
  val animatorset = animatorset()
  animatorset.playtogether(animx, animy) // 同时执行x、y轴的动画
  animatorset.interpolator = cycleinterpolator(2f)// 执行2次
  animatorset.duration = 500 // 1秒后结束
  animatorset.doonend {
   clearallinputvalues()
   animatorset.cancel()
  }
  animatorset.start()
 }
 
 /*输入框监听回调《供外部调用》*/
 private var oninputlistener: oninputlistener? = null
 fun setoninputlistener(oninputlistener: oninputlistener) {
  this.oninputlistener = oninputlistener
 }
 
 /*获取验证码点击回调《供外部调用》*/
 private var onclicksmscodetvlistener: onclicklistener? = null
 fun setonclicksmscodetvlistener(onclicksmscodetvlistener: onclicklistener){
  this.onclicksmscodetvlistener = onclicksmscodetvlistener
 }
 
}

 主要有两种显示样式,在枚举中定义了4个输入框6个输入框

基本调用代码如下:

//ll_sms_input就是customsmscodeinputlayout
ll_sms_input.run {
//里边的配置可以自行选择配置
   settoptipvisible(false)
   setcurrentcenterlinevisible(true)
   setbottomsmstvvisible(true)
   setshowinputnum(customsmscodeinputlayout.inputlinenum.six)//这里加载的是六个输入框
   setcurrentindexlinecolor(resources.getcolor(r.color.global_text_color_grey))
   //设置输入类型只能是数字
   setinputtype(inputtype.type_class_number or inputtype.type_number_flag_signed)
   showsoftinput()
  }
ll_sms_input.setoninputlistener()//做输入完成后的监听
ll_sms_input.setonclicksmscodetvlistener()//点击重新获取按钮的监听

总结

以上所述是小编给大家介绍的android实现自定义验证码输入框效果,希望对大家有所帮助