Android 自定義驗證碼輸入框




本文實現思路:6個TextView,上面覆蓋透明EditText接收輸入事件。

上代碼

VerificationCodeView

class VerificationCodeView @JvmOverloads constructor(
    context: Context?,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : RelativeLayout(context, attributeSet, defStyleAttr, defStyleRes) {
    private var view =
        LayoutInflater.from(context).inflate(R.layout.view_verification_code, this, true)
    private var tv1: TextView
    private var tv2: TextView
    private var tv3: TextView
    private var tv4: TextView
    private var tv5: TextView
    private var tv6: TextView
    private var et: EditText

    val codes = arrayListOf<String>()

    var block: ((Boolean) -> Unit)? = null

    init {
        tv1 = view.findViewById(R.id.tvVerification1)
        tv2 = view.findViewById(R.id.tvVerification2)
        tv3 = view.findViewById(R.id.tvVerification3)
        tv4 = view.findViewById(R.id.tvVerification4)
        tv5 = view.findViewById(R.id.tvVerification5)
        tv6 = view.findViewById(R.id.tvVerification6)
        et = view.findViewById(R.id.etVerification)

        setTextViews()

        et.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                if (!s.isNullOrEmpty()) {
                    et.setText("")
                    if (codes.size < 6) {
                        codes.add(s.toString())
                        setTextViews()
                    }
                }
                block?.invoke((codes.size == 6))
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            }

        })

        et.setOnKeyListener { _, keyCode, event ->
            if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN && codes.size > 0) {
                codes.removeAt(codes.size - 1)
                setTextViews()
                block?.invoke((codes.size == 6))
                true
            } else {
                false
            }
        }
    }

    private fun setTextViews() {
        setDefaultViews()
        codes.size.let {
            if (it >= 1) {
                tv1.text = codes[0]
            }
            if (it >= 2) {
                tv2.text = codes[1]
            }
            if (it >= 3) {
                tv3.text = codes[2]
            }
            if (it >= 4) {
                tv4.text = codes[3]
            }
            if (it >= 5) {
                tv5.text = codes[4]
            }
            if (it == 6) {
                tv6.text = codes[5]
            }

            when (it) {
                0 -> tv1.setBackgroundResource(R.drawable.bg_text_checked)
                1 -> tv2.setBackgroundResource(R.drawable.bg_text_checked)
                2 -> tv3.setBackgroundResource(R.drawable.bg_text_checked)
                3 -> tv4.setBackgroundResource(R.drawable.bg_text_checked)
                4 -> tv5.setBackgroundResource(R.drawable.bg_text_checked)
                5 -> tv6.setBackgroundResource(R.drawable.bg_text_checked)
            }
        }
    }

    private fun setDefaultViews() {
        tv1.text = ""
        tv2.text = ""
        tv3.text = ""
        tv4.text = ""
        tv5.text = ""
        tv6.text = ""
        tv1.setBackgroundResource(R.drawable.bg_text_normal)
        tv2.setBackgroundResource(R.drawable.bg_text_normal)
        tv3.setBackgroundResource(R.drawable.bg_text_normal)
        tv4.setBackgroundResource(R.drawable.bg_text_normal)
        tv5.setBackgroundResource(R.drawable.bg_text_normal)
        tv6.setBackgroundResource(R.drawable.bg_text_normal)
    }

    fun getText(): String {
        return if (codes.size == 0) ""
        else {
            var result = ""
            for (code in codes) {
                result += code
            }
            result
        }
    }

    fun setListener(block: (Boolean) -> Unit) {
        this.block = block
    }
}

view_verification_code.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tvVerification1"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/tvVerification2"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginStart="8dp"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/tvVerification3"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginStart="8dp"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/tvVerification4"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginStart="8dp"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/tvVerification5"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginStart="8dp"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/tvVerification6"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginStart="8dp"
            android:background="@drawable/bg_text_normal"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="22sp" />
    </LinearLayout>

    <EditText
        android:id="@+id/etVerification"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/transparent"
        android:cursorVisible="false"
        android:inputType="numberPassword"
        android:textColor="@color/transparent" />
</RelativeLayout>

bg_text_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:width="1dp"
        android:color="@color/gray_1A000000" />
</shape>

bg_text_checked.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:width="1dp"
        android:color="@color/blue_266EFF" />
</shape>

color.xml

    <color name="transparent">#00000000</color>
    <color name="gray_1A000000">#1A000000</color>
    <color name="blue_266EFF">#266EFF</color>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章