Method Example of Implementing Payment Password Numeric Keyboard by Kotlin Custom
- 2021-09-20 21:33:39
- OfStack
What can you learn
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