Hello啊老铁们,这篇文章还是阐述自定义View相关的内容,用Canvas轻轻松松搞一个数字键盘,本身没什么难度,这种效果实现的方式也是多种多样,这篇只是其中的一种,要说本篇有什么特别之处,可能就是纯绘制,没有用到其它的任何资源,一个类就搞定了,文中不足之处,各位老铁多包含,多指正。
本篇的内容大概如下:
1、效果展示
2、快速使用及属性介绍
3、具体代码实现
4、源文件地址及总结
一、效果展示
很常见的数字键盘,背景,颜色,文字大小,点击的事件等等,均已配置好,大家可以看第2项中相关介绍。
静态效果展示:
动态效果展示,录了一个gif,大家可以看下具体的触摸效果。
二、快速使用及属性介绍
鉴于本身就一个类,不值当去打一个远程的Maven,大家用的话可以直接下载,把文件复制到项目里即可,复制到项目中,就可以按照下面的步骤去使用。
引用
1、xml中引用,可以根据需要,设置宽高及相关属性
<KeyboardViewandroid:id="@+id/key_board_view"android:layout_width="match_parent"android:layout_height="wrap_content"/>
2、代码直接创建,然后追加到相关视图里即可
valkeyboardView=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) /3mPaint!!.strokeWidth=10ffor (iin0..11) { //设置方格valrect=RectF() valiTemp=i/3valrectTop=mHeight*iTemp+mSpacing* (iTemp+1f) rect.top=rectToprect.bottom=rect.top+mHeightvarleftSpacing= (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=mTextColorvarkeyWord="${i + 1}"//索引等于 10 从新赋值为 0if (i==10) { keyWord="0" } valrectWord=Rect() mPaint!!.getTextBounds(keyWord, 0, keyWord.length, rectWord) valwWord=rectWord.width() valhtWord=rectWord.height() varyWord=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 ((iin1..8) &&mIsShowLetter) { mPaint!!.textSize=mLetterTextSizevals=mWordArray[i-1] valrectW=Rect() mPaint!!.getTextBounds(s, 0, s.length, rectW) valw=rectW.width() valh=rectW.height() canvas.drawText( s, rect.right-mRectWidth!!/2- (w/2), rect.bottom-mHeight/2+h*2, mPaint!! ) }
4、关于删除按钮的绘制
删除按钮是纯线条的绘制,没有使用图片资源,不过大家可以使用图片资源,因为图片资源还是比较的靠谱。
/*** AUTHOR:AbnerMing* INTRODUCE:绘制删除按键,直接canvas自绘,不使用图片*/privatefundrawDelete(canvas: Canvas?, right: Float, top: Float) { valrWidth=15vallineWidth=35valx=right-mRectWidth!!/2- (rWidth+lineWidth) /4valy=top+mHeight/2valpath=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=30fvalcontent="×"valrectWord=Rect() mPaint!!.getTextBounds(content, 0, content.length, rectWord) valwWord=rectWord.width() valhtWord=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:返回触摸的位置*/privatefungetTouch(upX: Float, upY: Float): Int { varposition=-2for (iin0..11) { valiTemp=i/3valrectTop=mHeight*iTemp+mSpacing* (iTemp+1f) valtop=rectTopvalbottom=top+mHeightvarleftSpacing= (mSpacing* (i%3f)) leftSpacing+=10fvalleft=mRectWidth!!* (i%3f) +leftSpacingvalright=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 } } } returnposition }
在onDraw里进行改变画笔的颜色。
//按下的索引 和 方格的 索引一致,改变背景颜色if (mDownPosition== (i+1)) { mPaint!!.color=mDownBackGroundColor } else { mPaint!!.color=mRectBackGroundColor }
6、wrap_content处理
在使用当前控件的时候,需要处理wrap_content的属性,否则效果就会和match_parent一样了,具体的处理如下,重写onMeasure方法,获取高度的模式后进行单独的设置。
overridefunonMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) valheightSpecMode=MeasureSpec.getMode(heightMeasureSpec) valwidthSpecSize=MeasureSpec.getSize(widthMeasureSpec) if (heightSpecMode==MeasureSpec.AT_MOST) { //当高度为 wrap_content 时 设置一个合适的高度setMeasuredDimension(widthSpecSize, (mHeight*4+mSpacing*5+10).toInt()) } }
四、源文件地址及总结
源文件地址:
https://github.com/AbnerMing888/KeyboardView
源文件不是一个项目,是一个单纯的文件,大家直接复制到项目中使用即可,对于26个英文字母键盘绘制,基本上思路是一致的,大家可以在此基础上进行拓展,本文就先到这里吧,整体略有瑕疵,忘包含。