SoFunction
Updated on 2025-03-11

Example of method to customize payment password numeric keyboard for Kotlin

What can you learn

  • The use of kotlin, the writing of extended features, etc.
  • Some basics of custom ViewGroup
  • Writing and reading of xml properties

Because each key takes into account the need to support other personal settings such as background settings and Touch gestures, I decided to implement it with the idea of ​​each key corresponding to a View. Otherwise, I can use itaccomplish

This improves scalability and customizability

1. Define the keys according to the renderings

//First define the required keys//The order is disrupted, and the display is out of order, which can be safer.//Special keys-> "": means blank placeholder key; "-1": means back key, that is, delete.var keys = arrayOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "-1")

Update the corresponding keys and create the corresponding view

  {
  val keyView: View = when (it) {
   "-1" -> {
    //delete    imageView(.keyboard_del, .keyboard_del_press).apply {
     background = null
     setBackgroundColor(("#E2E7ED"))
    }
   }
   "" -> {
    //Placeholder View    View(context).apply {
     setBackgroundColor(("#E2E7ED"))
    }
   }
   else -> {
    createKeyView(it)
   }
  }

   = it //Save the corresponding value of the key through tag  addView(keyView)
 }

private fun createKeyView(key: String): View {
  return if (useImageKey) {
   val keyRes = when (key) {
    "1" -> .keyboard_1
    "2" -> .keyboard_2
    "3" -> .keyboard_3
    "4" -> .keyboard_4
    "5" -> .keyboard_5
    "6" -> .keyboard_6
    "7" -> .keyboard_7
    "8" -> .keyboard_8
    "9" -> .keyboard_9
    else -> .keyboard_0
   }
   imageView(keyRes)
  } else {
   textView(key)
  }
 }

 private fun imageView(res: Int, pressRes: Int = -1): ImageView {
  return ImageView(context).apply {

   if (pressRes == -1) {
    setImageResource(res)
   } else {
    setImageResource(res)
    //setImageDrawable((getDrawable(res), getDrawable(pressRes)))
   }

   scaleType = 

   keyViewBGDrawable?.let {
    background = ()
   }

   setOnClickListener(this@KeyboardLayout)
  }
 }

 private fun textView(text: String): TextView {
  return TextView(context).apply {
   gravity = 
    = text
   setTextSize(TypedValue.COMPLEX_UNIT_PX, keyTextSize)

   keyViewBGDrawable?.let {
    background = ()
   }
   setTextColor()

   setOnClickListener(this@KeyboardLayout)
  }
 }

2. After the key element is created, start the standard operation of customizing ViewGroup

onMeasure: Measure the width and height of each key

 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
  //(widthMeasureSpec, heightMeasureSpec)
  var widthSize = (widthMeasureSpec)
  val widthMode = (widthMeasureSpec)
  var heightSize = (heightMeasureSpec)
  val heightMode = (heightMeasureSpec)

  if (widthMode != ) {
   widthSize = 
  }

  if (heightMode != ) {
   heightSize = (4 * keyViewHeight + 3 * vSpace).toInt()
  }

  childWidth = ((widthSize - 2 * hSpace - paddingLeft - paddingRight) / 3).toInt()
  childHeight = ((heightSize - 3 * vSpace - paddingTop - paddingBottom) / 4).toInt()
  childs { _, view ->
   (exactlyMeasure(childWidth), exactlyMeasure(childHeight))
  }
  setMeasuredDimension(widthSize, heightSize)
 }

onLayout: Determines the coordinate position of the key in the ViewGroup

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
 //Lattach one line, 4 lines in total for (line in 0..3) {

  var top: Int = (paddingTop + line * (childHeight + vSpace)).toInt()

  //3 columns  for (i in 0..2) {
   var left: Int = (paddingLeft + i * (childWidth + hSpace)).toInt()

   getChildAt(line * 3 + i).layout(left, top, left + childWidth, top + childHeight)
  }
 }
}

3: Event listening and callback

 override fun onClick(v: View?) {
  if (onKeyboardInputListener == null) {
   return
  }

  v?.let { view ->
   val tag = 
   if (tag is String) {
    val isDel = "-1" == tag
    onKeyboardInputListener?.onKeyboardInput(tag, isDel)
   }
  }
 }

4: Properties declaration in xml

You need to create an XML file with any file name in the values ​​folder

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="KeyboardLayout">
  <attr name="r_key_height" format="dimension"/>
  <attr name="r_key_width" format="dimension"/>
  <attr name="r_key_text_size" format="dimension"/>
  <attr name="r_key_background" format="reference"/>
  <attr name="r_background" format="reference"/>
  <attr name="r_use_image_key" format="boolean"/>
 </declare-styleable>
</resources>

declare-styleable are both standard writing methods. Name corresponds to the type of custom view, and they are all standard writing methods. Different formats correspond to different get methods. It is easy to use when you are familiar with it.

5: Property reading in xml

 init {
  val typedArray = (attributeSet, ) //Note 1:  keyViewHeight = (.KeyboardLayout_r_key_height, keyViewHeight)
  //(.KeyboardLayout_r_key_width, keyViewHeight)
  keyTextSize = (.KeyboardLayout_r_key_text_size, keyTextSize)
  useImageKey = (.KeyboardLayout_r_use_image_key, useImageKey)

  keyViewBGDrawable = (.KeyboardLayout_r_key_background)

  if (keyViewBGDrawable == null) {
   keyViewBGDrawable = getDrawable(.base_white_bg_selector)
  }
  mBackgroundDrawable = (.KeyboardLayout_r_background)
  if (mBackgroundDrawable == null) {
   mBackgroundDrawable = ColorDrawable(getColor(.base_chat_bg_color))
  }

  setWillNotDraw(false)
  () //Note 2 }

Note 1,2:All are necessary writing methods, and the middle part is the corresponding attribute reading operation.

Source code address /angcyo/KeyboardLayout (Local download

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.