您的位置:首页 > 其它

Kotlin自定义实现支付密码数字键盘的方法实例

2018-07-22 15:44 816 查看

你能学到什么

  • kotlin的使用, 扩展特性的写法等
  • 自定义ViewGroup的一些基础知识
  • xml属性的编写和读取

因为每个按键都考虑到需要支持背景设置等其他个性设置和Touch手势的处理, 所以我决定采用 每个按键 对应一个View的思路实现. 否则可以使用

Canvas.drawText
实现

这样可以提高扩展性和可自定义性

1.根据效果图先定义按键

//首先定义需要的那些按键
//顺序打乱,展示的时候也就是乱序的,可以更安全.
//特殊按键-> "":表示空白占位按键; "-1":表示回退键, 也就是删除.
var keys = arrayOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "-1")

更新对应的按键, 创建对应的view

keys.forEach {
val keyView: View = when (it) {
"-1" -> {
//删除
imageView(R.drawable.keyboard_del, R.drawable.keyboard_del_press).apply {
background = null
setBackgroundColor(Color.parseColor("#E2E7ED"))
}
}
"" -> {
//占位View
View(context).apply {
setBackgroundColor(Color.parseColor("#E2E7ED"))
}
}
else -> {
createKeyView(it)
}
}
keyView.tag = it //通过tag, 保存按键对应的值
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.按键元素创建好之后, 开始自定义ViewGroup的标准操作

onMeasure:测量每个按键的宽度和高度

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:决定按键在ViewGroup中的坐标位置

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
//一行一行布局, 共4行
for (line in 0..3) {
var top: Int = (paddingTop + line * (childHeight + vSpace)).toInt()
//3列
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:事件监听和回调

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:xml中的属性声明

需要在 values 文件夹中创建一个任意文件名的xml文件

<?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 都是标准写法, name对应的就是自定义view的类型, 都是标准写法, 不同的format对应不同的get方法. 熟悉了就很容易使用.

5:xml中的属性读取

init {
val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.KeyboardLayout) //注意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() //注意2
}

注意1,2: 都是必备的写法, 中间部分才是对应的属性读取操作.

源码地址 https://github.com/angcyo/KeyboardLayout (本地下载

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

您可能感兴趣的文章:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kotlin 自定义 键盘
相关文章推荐