Method Example of Implementing Payment Password Numeric Keyboard by Kotlin Custom

  • 2021-09-20 21:33:39
  • OfStack

What can you learn

The use of kotlin, the writing of extended features, etc Some basic knowledge of customizing ViewGroup Writing and Reading xml Attribute

Because each key takes into account the need to support other personality settings such as background settings and the processing of Touch gestures, I decided to use the idea that each key corresponds to one View. Otherwise, you can use Canvas.drawText Realization

This improves scalability and customizability

1. Define the keys according to the renderings first


// Define the keys you need first 
// Out of order , It is out of order when it is displayed , It can be safer .
// Special keystrokes -> "": Indicates a blank placeholder button ; "-1": Represents the rollback key ,  That is, delete .
var keys = arrayOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "-1")

Update the corresponding key to create the corresponding view


 keys.forEach {
  val keyView: View = when (it) {
   "-1" -> {
    // Delete 
    imageView(R.drawable.keyboard_del, R.drawable.keyboard_del_press).apply {
     background = null
     setBackgroundColor(Color.parseColor("#E2E7ED"))
    }
   }
   "" -> {
    // Space occupying View
    View(context).apply {
     setBackgroundColor(Color.parseColor("#E2E7ED"))
    }
   }
   else -> {
    createKeyView(it)
   }
  }

  keyView.tag = it // Pass tag,  Save the value corresponding to the key 
  addView(keyView)
 }

private fun createKeyView(key: String): View {
  return if (useImageKey) {
   val keyRes = when (key) {
    "1" -> R.drawable.keyboard_1
    "2" -> R.drawable.keyboard_2
    "3" -> R.drawable.keyboard_3
    "4" -> R.drawable.keyboard_4
    "5" -> R.drawable.keyboard_5
    "6" -> R.drawable.keyboard_6
    "7" -> R.drawable.keyboard_7
    "8" -> R.drawable.keyboard_8
    "9" -> R.drawable.keyboard_9
    else -> R.drawable.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(ResUtil.selector(getDrawable(res), getDrawable(pressRes)))
   }

   scaleType = ImageView.ScaleType.CENTER

   keyViewBGDrawable?.let {
    background = it.constantState.newDrawable()
   }

   setOnClickListener(this@KeyboardLayout)
  }
 }

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

   keyViewBGDrawable?.let {
    background = it.constantState.newDrawable()
   }
   setTextColor(Color.BLACK)

   setOnClickListener(this@KeyboardLayout)
  }
 }

2. After the key elements are created, start customizing the standard operation of ViewGroup

onMeasure: Measure the width and height of each key


 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
  //super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  var widthSize = MeasureSpec.getSize(widthMeasureSpec)
  val widthMode = MeasureSpec.getMode(widthMeasureSpec)
  var heightSize = MeasureSpec.getSize(heightMeasureSpec)
  val heightMode = MeasureSpec.getMode(heightMeasureSpec)

  if (widthMode != MeasureSpec.EXACTLY) {
   widthSize = resources.displayMetrics.widthPixels
  }

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

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

onLayout: Determine the coordinate position of the key in ViewGroup


override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
 //1 Row 1 Row layout ,  Altogether 4 Row 
 for (line in 0..3) {

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

  //3 Column 
  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 Callbacks


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

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

4: Attribute declarations 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 standard writing, name corresponds to the type of custom view, are standard writing, different format corresponds to different get method. Familiar with it is easy to use.

5: Property reading in xml


 init {
  val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.KeyboardLayout) // Attention 1:
  keyViewHeight = typedArray.getDimensionPixelOffset(R.styleable.KeyboardLayout_r_key_height, keyViewHeight)
  //typedArray.getDimensionPixelOffset(R.styleable.KeyboardLayout_r_key_width, keyViewHeight)
  keyTextSize = typedArray.getDimension(R.styleable.KeyboardLayout_r_key_text_size, keyTextSize)
  useImageKey = typedArray.getBoolean(R.styleable.KeyboardLayout_r_use_image_key, useImageKey)

  keyViewBGDrawable = typedArray.getDrawable(R.styleable.KeyboardLayout_r_key_background)

  if (keyViewBGDrawable == null) {
   keyViewBGDrawable = getDrawable(R.drawable.base_white_bg_selector)
  }
  mBackgroundDrawable = typedArray.getDrawable(R.styleable.KeyboardLayout_r_background)
  if (mBackgroundDrawable == null) {
   mBackgroundDrawable = ColorDrawable(getColor(R.color.base_chat_bg_color))
  }

  setWillNotDraw(false)
  typedArray.recycle() // Attention 2
 }

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

Source address https://github.com/angcyo/KeyboardLayout (local download)

Summarize


Related articles: