热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要给大家介绍了关于Kotlin如何自定义实现支付密码数字键盘的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

你能学到什么

  • 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文件

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
  
  
  
  
  
  
 

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 (本地下载)

总结

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


推荐阅读
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 本文通过思维导图的形式,深入解析了大型网站技术架构的核心原理与实际案例。首先,探讨了大型网站架构的演化过程,从单体应用到分布式系统的转变,以及各阶段的关键技术和挑战。接着,详细分析了常见的大型网站架构模式,包括负载均衡、缓存机制、数据库设计等,并结合具体案例进行说明。这些内容不仅有助于理解大型网站的技术实现,还能为实际项目提供宝贵的参考。 ... [详细]
  • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • Git命令基础应用指南
    本指南详细介绍了Git命令的基础应用,包括如何使用`git clone`从远程服务器克隆仓库(例如:`git clone [url/path/repository]`)以及如何克隆本地仓库(例如:`git clone [local/path/repository]`)。此外,还提供了常见的Git操作技巧,帮助开发者高效管理代码版本。 ... [详细]
  • Git应用技巧与实战经验分享
    在使用 Git 进行代码管理时,有时会遇到无法访问 `https://github.com` 仓库的问题,具体表现为 OpenSSL SSL_read 错误,连接被重置(errno 10054)。本文将深入探讨这一问题的成因,并分享多种解决方法,包括检查网络配置、更新 Git 版本以及调整 SSL 设置等,帮助开发者有效应对类似问题。此外,文章还将介绍一些实用的 Git 技巧和实战经验,提升代码管理和协作效率。 ... [详细]
  • 在更换电脑后,使用 Git Bash 运行 Python 时可能会遇到找不到 Python 解释器的问题。本文详细介绍了如何在 Windows 环境下通过 Bash Shell 调用不同版本的 Python,并成功运行 SRSPlayer HTTP 服务器。具体步骤包括配置环境变量、验证 Python 版本以及启动服务器的方法。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 在本篇学习指南中,我们将探讨 Spring Cloud 2020 版本中的技术选型和版本选择策略。具体来说,我们将详细介绍如何在项目中选用 Spring Boot 和 Spring Cloud 的最佳组合。本文以 Spring Boot 2.2.2 为例,结合实际应用场景,提供详细的配置和使用建议,帮助开发者更好地理解和应用这些框架。此外,我们还将讨论不同版本之间的兼容性和升级路径,确保项目能够平稳过渡到最新版本。 ... [详细]
  • 在List和Set集合中存储Object类型的数据元素 ... [详细]
  • SIoU Loss 的原理详解及代码实现分析
    本文详细解析了 SIoU Loss 的原理及其在边界框回归任务中的优势,并通过代码实现对其性能进行了深入分析。SIoU Loss 作为一种改进的损失函数,能够更有效地优化目标检测模型的边界框回归效果,提升模型的准确性和鲁棒性。文中还提供了具体的代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
author-avatar
iar2984165
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有