android自定义view(自定义数字键盘)

序言:在上周的项目中,需要做一个密码锁的功能,然后密码下面还得有键盘,就类似支付宝支付的时候那样:

当然了,我们项目的需求简单点,纯数字的就可以了,然后上周就百度了自定义键盘,随便找了一个修改修改就用到项目中去了。

多谢这位简友:[Android] 自定义输入支付密码的软键盘

今天自己抽空写了一个自定义View的键盘控件,下面跟大家分享一下:

####思路: 1、布局:

(1)、宫格:我们可以将这个布局看成是宫格布局,然后需要计算出每个小宫格在屏幕中的位置(坐标),然后再用canvas画出相应的矩形即可。
(2)、数字:我们需要计算出每个小宫格中的中心点位置(坐标),然后用canvas画数字上去,当然,我们知道最后一个是删除键,并不是数字,我们可以准备一张图片,将图片画到相应的位置。
复制代码

2、用户动作:

(1)、按下:用户每一次按下的时候就表示这一次动作的开始,所以首先要将各种标识位(自定义所需要的标识位)设置成初始状态,然后需要记录按下的坐标,然后计算出用户按下的坐标与宫格中哪个点相对应,在记录相应数字。最后刷新布局
(2)、抬起:用户抬起的时候需要刷新布局,然后将按下过程中记录下的数字或者删除键信息通过接口的形式回调给用户,最后恢复标识位
(3)、取消:将所有的标识位恢复成初始状态。
复制代码

好了,思路就讲到这里,我们来看看onDraw方法:

protected void onDraw(Canvas canvas) {if (!isInit) {initData();}mPaint.setColor(Color.WHITE);//画宫格//第一排canvas.drawRoundRect(10, mHeight / 2 + 10, 10 + mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 10, 20 + 2 * mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 10, 30 + 3 * mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);//第二排canvas.drawRoundRect(10, mHeight / 2 + 20 + mRectHeight, 10 + mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 20 + mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 20 + mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);//第三排canvas.drawRoundRect(10, mHeight / 2 + 30 + 2 * mRectHeight, 10 + mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 30 + 2 * mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 30 + 2 * mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);//第四排mPaint.setColor(Color.GRAY);canvas.drawRoundRect(10, mHeight / 2 + 40 + 3 * mRectHeight, 10 + mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);mPaint.setColor(Color.WHITE);canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 40 + 3 * mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);mPaint.setColor(Color.GRAY);canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 40 + 3 * mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);mPaint.setColor(Color.BLACK);mPaint.setTextSize(60);// 设置字体大小mPaint.setStrokeWidth(2);//画数字//第一排canvas.drawText("1", xs[0], ys[0], mPaint);canvas.drawText("2", xs[1], ys[0], mPaint);canvas.drawText("3", xs[2], ys[0], mPaint);//第二排canvas.drawText("4", xs[0], ys[1], mPaint);canvas.drawText("5", xs[1], ys[1], mPaint);canvas.drawText("6", xs[2], ys[1], mPaint);//第三排canvas.drawText("7", xs[0], ys[2], mPaint);canvas.drawText("8", xs[1], ys[2], mPaint);canvas.drawText("9", xs[2], ys[2], mPaint);//第四排canvas.drawText(".", xs[0], ys[3], mPaint);canvas.drawText("0", xs[1], ys[3], mPaint);canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);
}
复制代码
注:上面的坐标需要我们自己算出,耐心一点,很容易算的,你只需要搞清楚在Android中屏幕是怎样的坐标系就可以了。坐标算出来之后,我们先画宫格,然后再画数字和删除键,这里有人要问了,我可以先画数字吗,NO,因为当你画完数字之后再画宫格你会发现数字不见了,为什么呢?**被你的宫格挡住了 >_<**所以千万别这样做。画的过程中别忘了将画笔设置一些你需要的属性。

好了,画好之后,我们来看看效果怎么样:

样式出来了哈!但是设计的没那么好看,大家将就看一看哈>_<

然后我们需要重写onTouch事件,在里面判断用户的一些行为:

switch (event.getAction()) {case MotionEvent.ACTION_DOWN: //按下//恢复默认值setDefault();/***判断按下的点在哪个宫格中*/invalidate();//刷新界面return true;case MotionEvent.ACTION_UP: //弹起invalidate();//刷新界面/***一次按下结束,返回点击的数字*///恢复默认setDefault();return true;case MotionEvent.ACTION_CANCEL:  //取消//恢复默认值setDefault();return true;}
复制代码

如上面伪代码所示,我写了一个方法来判断按下的点在哪个宫格中:

private void handleDown(float x, float y) {if (y < mHeight / 2) {return;}if (x >= 10 && x <= 10 + mRectWidth) {   //第一列clickX = xs[0];if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(1)clickY = ys[0];x1 = 10;y1 = mHeight / 2 + 10;x2 = 10 + mRectWidth;y2 = mHeight / 2 + 10 + mRectHeight;number = "1";} else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(4)x1 = 10;y1 = mHeight / 2 + 20 + mRectHeight;x2 = 10 + mRectWidth;y2 = mHeight / 2 + 20 + 2 * mRectHeight;clickY = ys[1];number = "4";} else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(7)x1 = 10;y1 = mHeight / 2 + 30 + 2 * mRectHeight;x2 = 10 + mRectWidth;y2 = mHeight / 2 + 30 + 3 * mRectHeight;clickY = ys[2];number = "7";} else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(0)x1 = 10;y1 = mHeight / 2 + 40 + 3 * mRectHeight;x2 = 10 + mRectWidth;y2 = mHeight / 2 + 40 + 4 * mRectHeight;clickY = ys[3];number = ".";}} else if (x >= 20 + mRectWidth && x <= 20 + 2 * mRectWidth) {  //第二列clickX = xs[1];if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(2)x1 = 20 + mRectWidth;y1 = mHeight / 2 + 10;x2 = 20 + 2 * mRectWidth;y2 = mHeight / 2 + 10 + mRectHeight;clickY = ys[0];number = "2";} else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(5)x1 = 20 + mRectWidth;y1 = mHeight / 2 + 20 + mRectHeight;x2 = 20 + 2 * mRectWidth;y2 = mHeight / 2 + 20 + 2 * mRectHeight;clickY = ys[1];number = "5";} else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(8)x1 = 20 + mRectWidth;y1 = mHeight / 2 + 30 + 2 * mRectHeight;x2 = 20 + 2 * mRectWidth;y2 = mHeight / 2 + 30 + 3 * mRectHeight;clickY = ys[2];number = "8";} else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(0)x1 = 20 + mRectWidth;y1 = mHeight / 2 + 40 + 3 * mRectHeight;x2 = 20 + 2 * mRectWidth;y2 = mHeight / 2 + 40 + 4 * mRectHeight;clickY = ys[3];number = "0";}} else if (x >= 30 + 2 * mRectWidth && x <= 30 + 3 * mRectWidth) {   //第三列clickX = xs[2];if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(3)x1 = 30 + 2 * mRectWidth;y1 = mHeight / 2 + 10;x2 = 30 + 3 * mRectWidth;y2 = mHeight / 2 + 10 + mRectHeight;clickY = ys[0];number = "3";} else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(6)x1 = 30 + 2 * mRectWidth;y1 = mHeight / 2 + 20 + mRectHeight;x2 = 30 + 3 * mRectWidth;y2 = mHeight / 2 + 20 + 2 * mRectHeight;clickY = ys[1];number = "6";} else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(9)x1 = 30 + 2 * mRectWidth;y1 = mHeight / 2 + 30 + 2 * mRectHeight;x2 = 30 + 3 * mRectWidth;y2 = mHeight / 2 + 30 + 3 * mRectHeight;clickY = ys[2];number = "9";} else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(删除键)x1 = 30 + 2 * mRectWidth;y1 = mHeight / 2 + 40 + 3 * mRectHeight;x2 = 30 + 3 * mRectWidth;y2 = mHeight / 2 + 40 + 4 * mRectHeight;clickY = ys[3];number = "delete";}}
}
复制代码

注:这个方法跟你之前计算出的宫格坐标有关系,所以一定不要计算错误

至此,我们写的差不多了,然后就是要提供一个接口,对外开放,方便用的时候调用,获取到数字或者其他信息:

public interface OnNumberClickListener {//回调点击的数字public void onNumberReturn(String number);//删除键的回调public void onNumberDelete();
}
复制代码

在onTouch事件中使用:

case MotionEvent.ACTION_UP: //弹起invalidate();//刷新界面//一次按下结束,返回点击的数字if (onNumberClickListener != null) {if (number != null) {if (number.equals("delete")) {onNumberClickListener.onNumberDelete();} else {onNumberClickListener.onNumberReturn(number);}}}//恢复默认setDefault();return true;
复制代码

然后我们来看一下效果怎么样吧!

功能也实现了,可是强迫症很强的我看着很不舒服,不知道你们有没有,好歹这也是一个键盘吧!按下弹起的效果都没有(没有改变按下的背景),在这里我们设置一个标志位,按下弹起刷新界面就可以了。在onTouch事件中改变该标识位的值,然后在onDraw方法中判断该标识位即可:

onTouch方法中增加:

case MotionEvent.ACTION_DOWN: //按下type=0;
case MotionEvent.ACTION_UP: //弹起type=1;
复制代码

onDraw方法增加:

        if (clickX > 0 && clickY > 0) {if (type == 0) {  //按下刷新if (number.equals("delete")) {mPaint.setColor(Color.WHITE);canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);} else {if (number.equals(".")) {mPaint.setColor(Color.WHITE);} else {mPaint.setColor(Color.GRAY);}canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);mPaint.setColor(Color.BLACK);mPaint.setTextSize(60);// 设置字体大小mPaint.setStrokeWidth(2);canvas.drawText(number, clickX, clickY, mPaint);}} else if (type == 1) {  //抬起刷新if (number.equals("delete")) {mPaint.setColor(Color.GRAY);canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);} else {if (number.equals(".")) {mPaint.setColor(Color.GRAY);} else {mPaint.setColor(Color.WHITE);}canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);mPaint.setColor(Color.BLACK);mPaint.setTextSize(60);// 设置字体大小mPaint.setStrokeWidth(2);canvas.drawText(number, clickX, clickY, mPaint);}//绘制完成后,重置clickX = 0;clickY = 0;}}
复制代码

接下来再来看看效果吧:

现在看起来舒服多了,~_~

代码我已经上传到Github传送门,欢迎大家fork,star

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/453333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux环境部署ltmj,Linux系统安装与简单配置 图文.docx

合肥师范学院实验报告姓名:课程名称&#xff1a;Linux院(系&#xff1a;计算机学院 专业/年级:实於Lin^系缭公装与苗瑕肚卅1.占克If Jf VVVork51at>un ?- If -JpMHIWortsktKia^2.?JGJiIjxiS4CLM.lt 1H. iuFI?H?*vW ?tVirtujl Machine Wisa rdGimm Oprraimv加蓟aBMkonA …

矩阵的压缩存储

5.3 矩阵的压缩存储 矩阵是很多科学与工程计算问题中研究的数学对象&#xff0c;在此&#xff0c;我们讨论如何存储矩阵的元&#xff0c;从而使矩阵的各种运算能有效第进行。对于一个矩阵结构显然用一个二维数组来表示是非常恰当的&#xff0c;但在有些情况下&#xff0c;比如常…

网络工程师还要学linux吗,网络工程师要学什么

想成为一个优秀的网络工程师&#xff0c;要学什么&#xff0c;怎么学呢?今天小编带你了解一下网络工程师到底要学什么。上篇我们讲到了“网络工程师发展方向”&#xff0c;列举了许多技术方向&#xff0c;那么我们该如何根据自己的定位选择学习哪些技术。重点是哪些&#xff0…

利用FormData对象实现AJAX文件上传功能及后端实现

包括HTML基础设置、CSS界面优化、JS利用FormData对象和AJAX进行上传、后端接收文件并存储到指定路径以及删除文件操作。FE HTML 基础的设置&#xff1a; <form enctype"multipart/form-data"><input id"file" type"file" multiple"…

第 6 章 —— 装饰模式

6.6 装扮模式总结 装饰模式把每个要装饰的功能放在单独的类中&#xff0c;并让这个类包装它所要装饰的对象&#xff0c;因此&#xff0c;当需要执行特殊行为时&#xff0c;客户端代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。 装扮模式是为已有功能动…

广义表及其存储方式简介

广义表&#xff08;Lists&#xff0c;又称列表&#xff09;是线性表的推广。线性表定义为n>0个元素a1,a2,a3,…,an的有限序列。线性表的元素仅限于原子项&#xff0c;原子是作为结构上不可分割的成分&#xff0c;它可以是一个数或一个结构&#xff0c;若放松对表元素的这种限…

Vue.js:路由

ylbtech-Vue.js&#xff1a;路由1.返回顶部 1、Vue.js 路由 本章节我们将为大家介绍 Vue.js 路由。 Vue.js 路由允许我们通过不同的 URL 访问不同的内容。 通过 Vue.js 可以实现多视图的单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。 Vue.…

图片转excel:“保留数字格式”在什么场景下该勾

保留数字格式是什么意思呢&#xff1f;顾名思义&#xff0c;就是将转出来的数字保留为数字格式&#xff0c;而不是文本格式。我们知道&#xff0c;OCR程序将图片上的文字识别为电脑可编辑的文字后&#xff0c;如果导入到excel不加处理&#xff0c;则单个数字过长的文字就会被ex…

html概述和基本结构

html概述 HTML是 HyperText Mark-up Language 的首字母简写&#xff0c;意思是超文本标记语言&#xff0c;超文本指的是超链接&#xff0c;标记指的是标签&#xff0c;是一种用来制作网页的语言&#xff0c;这种语言由一个个的标签组成&#xff0c;用这种语言制作的文件保存的是…

linux添加三权,基于SELinux的三权分离技术的研究

目前&#xff0c;Linux操作系统已广泛应用于各种设备和产品中&#xff0c;如服务器、PC机、机顶盒及路由器等。随着Linux系统的不断发展和广泛应用&#xff0c;Linux系统的安全问题也引起越来越多的关注。在Linux操作系统中&#xff0c;存在一个超级用户即root用户。root也称为…

二叉树、树和有序树的区别

树&#xff1a;子树没有左右之分 二叉树、有序树:左右有序 二叉树与有序树&#xff1a;在只有一棵树的情况下&#xff0c;二叉树有左右之分、有序树无左右之分 另外&#xff1a;二叉树是有序的&#xff0c;可以为空或一个根节点以及两个分别称为左子树和右子树的互不相交的二叉…

高效程序员

软件开发人员的作战手册 - 让程序员活的久一点 1. 程序员的职业准则是&#xff1a;诚实&#xff08;如实的报告你的状态&#xff0c;风险和出现的问题&#xff09;&#xff0c;守信&#xff08;承诺完成的任务就要按时完成&#xff09;&#xff0c;尊重&#xff08;尊重给你的代…

PHP学习笔记1

1.什么是PHP&#xff1f; Hypertext Preprocessor(超文本预处理语言)。 是脚本语言。 是最流行的网站开发语言。 2.PHP能做什么&#xff1f; 可以生成动态页面内容。 可以创建、打开、读取、写入、关闭服务器上的文件。 可以手机表单数据。 可以发送和接收cookies。&#xf…

Redis在windows下的配置

原文:Redis在windows下的配置 Redis在windows下的配置&#xff08;在windows-64下安装redis&#xff0c;请参考微软redis的github&#xff1a;https://github.com/MSOpenTech/redis/releases&#xff09;下面是windows32的配置 下载地址http://files.cnblogs.com/files/cuiweny…

linux磁盘符变化autofs,Linux基础教程学习笔记之Autofs自动挂载

Linux基础教程学习笔记之Autofs自动挂载Autofs自动挂载&#xff1a;yum -y install autofsvim /etc/auto.master 在文件中添加下面行/home/guests /etc/auto.tianyunvim /etc/auto.tianyun 子挂载点监控ldapuser0 -rw,sync classroom:/home/guests/ldapuser0systemctl enable …

二叉树的递归遍历(先序,中序,后序)

#include "stdio.h" #include "malloc.h" #define M 100 typedef struct node { /* 采用二叉链表存储结构 */char data;struct node *lchild,*rchild; }BTnode; BTnode *create()/*利用先序遍历的过程创建二叉树*/ {BTnode *t;char ch;scanf("%c&quo…

DOM-动态操作心得

这个知识点都是之前看过的,就当是复习了 一、创建元素的三种方法 第一种: document.write() 识别标签但会覆盖之前内容第二种: 用元素自身的innerHTML方法 不识别标签但可以不覆盖之前内容 ul.innerHTML "<li></li>"; 第三种:利用DOM自身api创建元素 …

linux探索之旅pdf,【Linux探索之旅】第四部分第一課:壓縮文件,解壓無壓力

內容簡介1、第四部分第一課&#xff1a;壓縮文件&#xff0c;解壓無壓力2、第四部分第二課&#xff1a;SSH連接&#xff0c;安全快捷壓縮文件&#xff0c;解壓無壓力最近小編因為換工作&#xff0c;從南法搬到巴黎。折騰了很久。網絡一直用的是公共的無線網&#xff0c;信號不行…

遍历二叉树的全部方法(递归+非递归)

#include<iostream> #include<queue> #include<stack> using namespace std; //二叉树结点的描述 typedef struct BiTNode { char data; struct BiTNode *lchild, *rchild; //左右孩子 }BiTNode,*BiTree; //按先序遍…

如何在本地搭建一个Android应用crashing跟踪系统-ACRA

https://github.com/bboyfeiyu/android-tech-frontier/tree/master/others/%E5%A6%82%E4%BD%95%E5%9C%A8%E6%9C%AC%E5%9C%B0%E6%90%AD%E5%BB%BA%E4%B8%80%E4%B8%AAAndroid%E5%BA%94%E7%94%A8crashing%E8%B7%9F%E8%B8%AA%E7%B3%BB%E7%BB%9F%EF%BC%8DACRA 如何在本地搭建一个Andr…