Kotlin–›自定义实现支付密码数字键盘

栏目: 编程语言 · XML · 发布时间: 6年前

内容简介:因为每个按键都考虑到需要支持背景设置等其他个性设置和Touch手势的处理, 所以我决定采用 每个按键 对应一个View的思路实现. 否则可以使用Canvas.drawText实现这样可以提高扩展性和可自定义性更新对应的按键, 创建对应的view

你能学到什么

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

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

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

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

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

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

<code> 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)
  }
</code>
<code>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)
     }
 }
</code>

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

引爆点

引爆点

[美] 马尔科姆·格拉德威尔 / 钱清、覃爱冬 / 中信出版社 / 2006-1 / 29.80元

这本书是《纽约客》杂志专职作家马尔科姆·格拉德威尔的一部才华横溢之作。他以社会上突如其来的流行风潮研究为切入点,从一个全新的角度探索了控制科学和营销模式。他认为,思想、行为、信息以及产品常常会像传染病爆发一样,迅速传播蔓延。正如一个病人就能引起一场全城流感;如果个别工作人员对顾客大打出手,或几位涂鸦爱好者管不住自己,也能在地铁里掀起一场犯罪浪潮;一位满意而归的顾客还能让新开张的餐馆座无虚席。这些现......一起来看看 《引爆点》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换