用Canvas绘制一个数字键盘
创始人
2024-01-22 08:18:33

Hello啊老铁们,这篇文章还是阐述自定义View相关的内容,用Canvas轻轻松松搞一个数字键盘,本身没什么难度,这种效果实现的方式也是多种多样,这篇只是其中的一种,要说本篇有什么特别之处,可能就是纯绘制,没有用到其它的任何资源,一个类就搞定了,文中不足之处,各位老铁多包含,多指正。

今天的内容大概如下:

1、效果展示

2、快速使用及属性介绍

3、具体代码实现

4、源文件地址及总结

一、效果展示

很常见的数字键盘,背景,颜色,文字大小,点击的事件等等,均已配置好,大家可以看第2项中相关介绍。

静态效果展示:

动态效果展示,录了一个gif,大家可以看下具体的触摸效果。

二、快速使用及属性介绍

鉴于本身就一个类,不值当去打一个远程的Maven,大家用的话可以直接下载,把文件复制到项目里即可,复制到项目中,就可以按照下面的步骤去使用。

引用

1、xml中引用,可以根据需要,设置宽高及相关属性

2、代码直接创建,然后追加到相关视图里即可

val keyboardView=KeyboardView(this)

方法及属性介绍

单个点击的触发监听:

keyboardView.setOnSingleClickListener {//键盘点击的数字}

获取最终的字符串点击监听,其实就是把你点击的数字拼接起来,一起输出,特别在密码使用的时候,省的你再自己拼接了,配合number_size属性和setNumberSize方法一起使用,默认是6个长度,可以根据需求,动态设置。

keyboardView.setOnNumClickListener {//获取最终的点击数字字符串,如:123456,通过number_size属性或setNumberSize方法,设置最长字符}

其它方法

方法

参数

概述

hintLetter

无参

隐藏字母

setBackGroundColor

int类型的颜色值

设置整体背景色

setRectBackGroundColor

int类型的颜色值

设置数字格子背景色

setTextColor

int类型的颜色值

设置文字颜色

setTextSize

Float

设置数字大小

setNumberSize

int类型

设置按下的数字总长度

setRectHeight

Float

设置数字键盘每格高度

setSpacing

Float

设置数字键盘每格间隔距离

属性介绍

属性

类型

概述

background_color

color

背景颜色

rect_background_color

color

数字格子背景色

down_background_color

color

手指按下的背景颜色

text_color

color

文字颜色

text_size

dimension

文字大小

letter_text_size

dimension

字母的文字大小

rect_height

dimension

数字格子高度

rect_spacing

dimension

格子间距

is_rect_letter

boolean

是否显示字母

number_size

integer

按下的数字总长度字符

三、具体代码实现

代码实现上其实也没有什么难的,主要就是用到了自定义View中的onDraw方法,简单的初始化,设置画笔,默认属性就不一一介绍了,直接讲述主要的绘制部分,我的实现思路如下,第一步,绘制方格,按照UI效果图,应该是12个方格,简图如下,需要注意的是,第10个是空的,也就是再绘制的时候,需要进行跳过,最后一个是一个删除的按钮,绘制的时候也需要跳过,直接绘制删除按钮即可。

1、关于方格的绘制

方格的宽度计算很简单,(手机的宽度-方格间距*4)/3即可,绘制方格,直接调用canvas的drawRoundRect方法,单纯的和数字一起绘制,直接遍历12个数即可,记住9的位置跳过,11的位置,绘制删除按钮。

mRectWidth = (width - mSpacing * 4) / 3
mPaint!!.strokeWidth = 10f
for (i in 0..11) {//设置方格val rect = RectF()val iTemp = i / 3val rectTop = mHeight * iTemp + mSpacing * (iTemp + 1f)rect.top = rectToprect.bottom = rect.top + mHeightvar leftSpacing = (mSpacing * (i % 3f))leftSpacing += mSpacingrect.left = mRectWidth!! * (i % 3f) + leftSpacingrect.right = rect.left + mRectWidth!!//9的位置是空的,跳过不绘制if (i == 9) {continue}//11的位置,是删除按钮,直接绘制删除按钮if (i == 11) {drawDelete(canvas, rect.right, rect.top)continue}mPaint!!.textSize = mTextSizemPaint!!.style = Paint.Style.FILL//按下的索引 和 方格的 索引一致,改变背景颜色if (mDownPosition == (i + 1)) {mPaint!!.color = mDownBackGroundColor} else {mPaint!!.color = mRectBackGroundColor}//绘制方格canvas!!.drawRoundRect(rect, 10f, 10f, mPaint!!)
}

2、关于数字的绘制

没有字母显示的情况下,数字要绘制到中间的位置,有字母的情况下,数字应该往上偏移,让整体进行居中,通过方格的宽高和自身文字内容的宽高来计算显示的位置。

//绘制数字mPaint!!.color = mTextColorvar keyWord = "${i + 1}"//索引等于 10 从新赋值为 0if (i == 10) {keyWord = "0"}val rectWord = Rect()mPaint!!.getTextBounds(keyWord, 0, keyWord.length, rectWord)val wWord = rectWord.width()val htWord = rectWord.height()var yWord = rect.bottom - mHeight / 2 + (htWord / 2)//上移if (i != 0 && i != 10 && mIsShowLetter) {yWord -= htWord / 3}canvas.drawText(keyWord,rect.right - mRectWidth!! / 2 - (wWord / 2),yWord,mPaint!!)

3、关于字母的绘制

因为字母是和数字一起绘制的,所以需要对应的字母则向下偏移,否则不会达到整体居中的效果,具体的绘制如下,和数字的绘制类似,拿到方格的宽高,以及字母的宽高,进行计算横向和纵向位置。

//绘制字母if ((i in 1..8) && mIsShowLetter) {mPaint!!.textSize = mLetterTextSizeval s = mWordArray[i - 1]val rectW = Rect()mPaint!!.getTextBounds(s, 0, s.length, rectW)val w = rectW.width()val h = rectW.height()canvas.drawText(s,rect.right - mRectWidth!! / 2 - (w / 2),rect.bottom - mHeight / 2 + h * 2,mPaint!!)}

4、关于删除按钮的绘制

删除按钮是纯线条的绘制,没有使用图片资源,不过大家可以使用图片资源,因为图片资源还是比较的靠谱。

/*** AUTHOR:AbnerMing* INTRODUCE:绘制删除按键,直接canvas自绘,不使用图片*/private fun drawDelete(canvas: Canvas?, right: Float, top: Float) {val rWidth = 15val lineWidth = 35val x = right - mRectWidth!! / 2 - (rWidth + lineWidth) / 4val y = top + mHeight / 2val path = Path()path.moveTo(x - rWidth, y)path.lineTo(x, y - rWidth)path.lineTo(x + lineWidth, y - rWidth)path.lineTo(x + lineWidth, y + rWidth)path.lineTo(x, y + rWidth)path.lineTo(x - rWidth, y)path.close()mPaint!!.strokeWidth = 2fmPaint!!.style = Paint.Style.STROKEmPaint!!.color = mTextColorcanvas!!.drawPath(path, mPaint!!)//绘制小×号mPaint!!.style = Paint.Style.FILLmPaint!!.textSize = 30fval content = "×"val rectWord = Rect()mPaint!!.getTextBounds(content, 0, content.length, rectWord)val wWord = rectWord.width()val htWord = rectWord.height()canvas.drawText(content,right - mRectWidth!! / 2 - wWord / 2 + 3,y + htWord / 3 * 2 + 2,mPaint!!)}

5、按下效果的处理

按下的效果处理,重写onTouchEvent方法,然后在down事件里通过,手指触摸的XY坐标,判断当前触摸的是那个方格,记录下索引,并使用invalidate进行刷新View,在onDraw里进行改变画笔的颜色即可。

根据XY坐标,返回触摸的位置

/*** AUTHOR:AbnerMing* INTRODUCE:返回触摸的位置*/private fun getTouch(upX: Float, upY: Float): Int {var position = -2for (i in 0..11) {val iTemp = i / 3val rectTop = mHeight * iTemp + mSpacing * (iTemp + 1f)val top = rectTopval bottom = top + mHeightvar leftSpacing = (mSpacing * (i % 3f))leftSpacing += 10fval left = mRectWidth!! * (i % 3f) + leftSpacingval right = left + mRectWidth!!if (upX > left && upX < right && upY > top && upY < bottom) {position = i + 1//位置11默认为 数字  0if (position == 11) {position = 0}//位置12  数字为 -1 意为删除if (position == 12) {position = -1}}}return position}

在onDraw里进行改变画笔的颜色。

 //按下的索引 和 方格的 索引一致,改变背景颜色if (mDownPosition == (i + 1)) {mPaint!!.color = mDownBackGroundColor} else {mPaint!!.color = mRectBackGroundColor}

6、wrap_content处理

在使用当前控件的时候,需要处理wrap_content的属性,否则效果就会和match_parent一样了,具体的处理如下,重写onMeasure方法,获取高度的模式后进行单独的设置。

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)if (heightSpecMode == MeasureSpec.AT_MOST) {//当高度为 wrap_content 时 设置一个合适的高度setMeasuredDimension(widthSpecSize, (mHeight * 4 + mSpacing * 5 + 10).toInt())}}

四、源文件地址及总结

源文件地址:

https://github.com/AbnerMing888/KeyboardView

源文件不是一个项目,是一个单纯的文件,大家直接复制到项目中使用即可,对于26个英文字母键盘绘制,基本上思路是一致的,大家可以在此基础上进行拓展,本文就先到这里吧,整体略有瑕疵,忘包含。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...