Android 自定义之我去年买了个表

前言:
          这是自定义view的的第二篇文章,自定义view是android工程师进阶必备的技能点,所以要想往中高级工程师发展,必须要学会之定义view,好多人说自定义比较难,其实不然,自定义view只不过比较繁琐,需要注意的点比较多,比如:测量、布局、绘制,就绘制来说就够你看一周也看不完,当然还有和view的交互等,所以一定要静下心来,不急不躁,循序渐进的去学,下面我们来绘制一个表玩玩。

先看下效果图(下面我们将分步来绘制,便于你的理解):

这里写图片描述


初始化:

这里写图片描述
注释已经很清楚了,我主要说下这个方法:

 protected void onSizeChanged(int w, int h, int oldw, int oldh)

这个方法在视图大小发生改变时调用。所以我们在这里获取宽高,只需要关注前两个参数。


绘制外部圆:

接下来的代码全是在onDraw()方法中执行:
这里写图片描述
相信了解Canva和Paint的童鞋一定对画圆API很熟悉,四个参数分别是:
圆心X坐标:mWidth / 2
圆心Y坐标: mHeight / 2
圆半径:mRadius
画笔对象: mCirclePaint
这个想必也不用解释了~


绘制刻度以及刻度值:

这里写图片描述

由于里面加的注释太多,可能图片有点不清晰,建议放大查看
表里面有粗体刻度和小刻度,粗体刻度就是整点时刻,这个比较容易理解。那我们的表盘刻度值一共有60个,所以我决定循环画出,当然了,循环体会区别粗体和小刻度:

粗体刻度:表盘中分别有12,1,2……11 只要是被5整除的就是粗体刻度。说白了就是画一条线段,注意看这个方法:

 //如图1:A点坐标(mWidth / 2, mHeight / 2 - mWidth / 2) B点(mWidth / 2, mHeight / 2 - mWidth / 2 + 60, mDegreePaint)
canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 60, mDegreePaint);

图1

为了促进我们的理解,我们结合图来看:
android坐标系不同于数学坐标系,android中以内容布局的左上角为坐标原点,水平向右为X轴正方向,垂直向下为Y轴正方向,如图我们的A点坐标(mWidth / 2, mHeight / 2 - mWidth / 2),B点(mWidth / 2, mHeight / 2 - mWidth / 2 + 60, mDegreePaint)其实就是两点决定一条直线,好了这是粗体刻度,那小刻度也一样道理,只不过短了一点,已经很详细了~

绘制刻度值

 String num = String.valueOf(i / 5);
        if ("0".equals(num)) {
            num = "12";
                            }
//绘制时间数值,X坐标:半径-数值文本宽度一半    Y坐标:90
canvas.drawText(num, mWidth / 2 - mDegreePaint.measureText(num) / 2, mHeight / 2 - mWidth / 2 + 90, mDegreePaint);

API我就不说了,一看就懂,我们绘制文本肯定是从文本左边底部开始时绘制,也就是坐下方位,什么还不明白?
这里写图片描述
简单说下坐标:
O是圆心
M点是 “12” 文本的X坐标中心点(你就把12看做是一个矩形框)M点就是矩形框底边的中间点
L就是我刚才说的左下坐标,我们绘制文本开始的地方,处于12的底部且左边
H是以L点为起始点,连接LH平行于MO
这下就比较好讲了:我们的目的就是求出L点坐标?
圆的半径=mWidth/2
点L的X坐标=mWidth/2-LM
LM是什么?12的宽度的一半,android已经有API可以求出文本宽度了:mDegreePaint.measureText(num)
点L的Y坐标就是距离X轴的距离,这个就是比较随意了。比如我们设置90
所以点L( mWidth / 2 - mDegreePaint.measureText(num) / 2, mHeight / 2 - mWidth / 2 + 90 )
是不是很简单?

可能有人会骂街!你这个是首个垂直刻度,其他倾斜的刻度呢!吓得我菊花一紧:

看码,哦不!看代码:

//画布旋转操作:一圈360度,共有60个刻度格,每个6度,所以每次旋转6度,也就是下面方法的第一个参数,后面两个参数其实就是旋转中心
canvas.rotate(6, mWidth / 2, mHeight / 2);

Canvas提供 位移、缩放、 旋转、错切,上面我们就是利用了旋转姿势~
这样我们只需要在for循环调用这个方法,刻度就会一一绘制出来。是不是很happy~


绘制指针:

这里写图片描述

绘制时针:
赶快拿出你去年买的表!接下来用得着!

canvas.rotate((hour * 5*6)+(minute*0.5f),mWidth/2,mHeight/2);
canvas.drawLine(mWidth/2,mHeight/2, mWidth / 2, mHeight / 2 - mWidth / 2 + 250, mHourPaint);

我们知道时针转走过一个小时,扫描的角度是:30度=5*6; 也就是5个刻度格 x每个刻度度数;
但这都是整时刻扫过的角度,我们要不是整时刻呢?比如5:08;所以我们还要加上分钟扫过的角度;
试想:分钟转一圈,我们的时针扫描30度,也就是说 0.5度/min (每分钟时针扫描0.5度)
好了,这就是时针计算过程!
那么还有两个API说明下:
canvas.save() :就是我们在做新的操作之前,先把以前画过的东西保存起来,也就是保存状态
canvas.restore():就是恢复save()之前的操作,保留现在的操作,我觉得就是合并的意思(个人理解)

分针和秒针

//分针
canvas.save();
canvas.rotate(minute * 6,mWidth/2,mHeight/2);
canvas.drawLine(mWidth/2,mHeight/2, mWidth / 2, mHeight / 2 - mWidth / 2 + 150, mMinutePaint);
canvas.restore();
//秒针
canvas.save();
canvas.rotate(second * 6,mWidth/2,mHeight/2);
canvas.drawLine(mWidth/2,mHeight/2, mWidth / 2, mHeight / 2 - mWidth / 2 + 100, mSecondPaint);
canvas.restore();

这里就不做解释了比较简单~
我们的秒针必须要每秒刷新一次,才能模拟钟表,所以调用 postInvalidateDelayed(1000);重新绘制onDraw()


方法说明:

我们上面主要是运用了画布(Canvas)的旋转,当然画布还有其他操作:
如:
位移(translate)
缩放(scale)
错切(skew)
这些都是画布的基本操作,有兴趣的可以自行google,毕竟网上教程很多,我就不多说了。


案例推荐:


github地址(如果喜欢,请亲~给个start 谢谢~)
这里写图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值