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

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

多谢这位简友:[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

android自定义view(自定义数字键盘)相关推荐

  1. vue实现自定义身份证,数字键盘(光标,输入框,键盘)

    vue实现自定义身份证,数字键盘(光标,输入框,键盘) 组件介绍 组件代码 效果图 组件使用 引用 使用 参数介绍 方法 插槽 组件介绍 vue实现自定义身份证键盘(光标,输入框,键盘全手写) 组件代 ...

  2. Android自定义View 自定义组合控件

    自定义组合控件: 以三国杀游戏武将为例,包括武将头像,血条,装备区 1.先定义该组合的XML文件布局 1 <?xml version="1.0" encoding=" ...

  3. android EditText 弹出数字键盘

    android EditText 弹出数字键盘 在xml中添加属性 android:digits="1234567890." 设置输入类型 txtBarCode.setInputT ...

  4. Android自定义View之数字密码锁

    距上次写博客已经快一年了,计划赶不上变化,种种原因加上自己的拖延症= =. 之前想好的每月一文还是没能坚持下来,趁着闲暇之余撸一篇,希望之后能够继续坚持总结的习惯.最近项目上用到一个密码加锁功能,需要 ...

  5. Android开发自定义View实现数字与图片无缝切换的2048

    本博客地址:http://blog.csdn.net/talentclass_ctt/article/details/51952378 最近在学自定义View,无意中看到鸿洋大神以前写过的2048(附 ...

  6. android 自定义view控件,Android 自定义View——自定义View控件

    Android给我们提供了大量的View控件,但这还是远远满足不了我们的要求,有时候开发所需要的控件形式是在Android提供的控件中是不存在,这就需要我们自己去定义一个.那么如何自定义控件? 学习自 ...

  7. 【Kotlin】Kotlin 自定义组件 ( 自定义 View | 自定义 SurfaceView )

    文章目录 一.自定义 View 组件 ( Kotlin ) 二.自定义 SurfaceView 组件 ( Kotlin ) 自定义组件构造函数统一在 constructor(context: Cont ...

  8. android 数字时钟代码大全,Android自定义view实现数字时钟

    最近在项目中遇到了一个需要实时更新时间的需求,并且用的地方还是挺多的,无奈做了一个简单的view来时现这个数字时钟. 首先看一下效果,比较简单,就是显示时分秒. 实现思路比较简单,利用handler的 ...

  9. 自定义View 实现软键盘实现搜索

    1. xml文件中加入自定义 搜索view <com.etoury.etoury.ui.view.IconCenterEditTextandroid:id="@+id/search_e ...

最新文章

  1. C# access update 出错总结,注意事项
  2. 环境测试明日最后一天 16万次公交车确保市民出行
  3. dubbo Trace 日志追踪
  4. printf的使用和test的使用
  5. 3、常用关键字,变量赋值,多个变量赋值,标准数据类型,数字,字符串,列表,元组,字典,数据类型转换
  6. 多版本JDK切换方式
  7. Spring MVC – Flash属性
  8. iis服务器显示http1.1,IIS服务器“500”内部错误 HTTP/1.1 新建会话失败
  9. c语言leg 10,Leg massaging device
  10. 面试官:说说Mysql数据库分库分表,并且会有哪些问题?
  11. [转]利用C#操作配置文件
  12. Microsoft Softwares
  13. 番茄时间管理法——学会专注
  14. python调节电脑音量_python如何调节音量大小
  15. 同步发电机转子的转动惯量与运动方程(一) 基本物理概念
  16. Vant组件库 引入 阿里矢量图 添加自己喜欢的 ICON
  17. 最新Flutter 微信分享功能实现
  18. Rust LLDB 调试入门指北
  19. java获取pdf文件首页图片,用来当做封面
  20. android studio 遇到 app error launching怎么办?

热门文章

  1. php长轮询阻塞,ajax长轮询时php被阻塞
  2. 《关于我的那些面经》——百度后端(附答案)
  3. leetcode209. 长度最小的子数组 借这个题规范一下双指针写法
  4. signature=4abdf782f13579fc1b57d94a0c6ce95c,β-lactam-associated eosinophilic colitis
  5. 小米用户画像_企鹅智库:高学历用苹果中老年用华为 男性用小米女性用OV
  6. 英语口语 week12 Thursday
  7. 年买笔记本的8个小技巧 最适合自己才最好(组图)
  8. C++回调函数(callback)的使用
  9. 苹果面试8大难题及答案
  10. 分布式开放 消息系统 (RocketMQ) 的原理与实践