SurfaceView打造自定义时钟ClockView
来源:互联网 发布:lol国服有mac版 编辑:程序博客网 时间:2024/05/17 22:41
从事Android开发也一段时间了,一直有做云笔记的习惯,但是博客不怎么写。最近给自己定了个计划,坚持每周至少写三个自定义控件,所谓熟能生巧呀。作为第一篇写的博客,给大家带来用SurfaceView打造的自定义时钟。PS:最近看见洋神的一篇推送,有人写了这个,自己看着效果图就写了哈哈,至少效果感觉还阔以O(∩_∩)O
先看下这炫酷的效果哈哈(时钟上的横线是录制的原因,效果是没有那根线的,不影响哈):
先简单介绍一下surfaceView吧,surfaceView区别于普通的View,其拥有以下特点:
①拥有独立的绘图表面。
②surfaceView需要在宿主上挖一个洞来显示自己。
③其的UI绘制可以在独立的进程中进行,使用双缓冲机制,不会阻塞主线程的UI操作。
那么,喜欢刨根问底的朋友们又会有疑问了,到底什么是双缓冲机制?
在surfaceView里面,所谓的双缓冲机制其实就是说SurfaceView分front和back两块画布,这两块画布会相互交替来显示,每post一次交替一次,交替后显示在surfaceView上面。(这只是查阅资料之后的粗略理解),有兴趣的朋友可以自己深入研究哈O(∩_∩)O
那么为什么要使用双缓冲机制?
那是为了解决某种情况下(例如游戏场景)UI反复的局部刷新带来的闪烁问题。
好了,基本知识点已经介绍完毕,咱们开始撸码咯\(^o^)/~
首先,要使用surfaceView,一些基本的代码使有套路的。通常一个surfaceView的基本框架如下:
public class ClockSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private Canvas mCanvas; private Paint mPaint; private boolean isDrawing; private SurfaceHolder mHolder; public ClockSurfaceView(Context context) { super(context); init(); } public ClockSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mHolder = getHolder(); mHolder.addCallback(this); setFocusable(true); setFocusableInTouchMode(true); setKeepScreenOn(true); mPaint = new Paint(); mPaint.setColor(Color.BLACK); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); } @Override public void surfaceCreated(SurfaceHolder holder) { new Thread(this).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } private void draw() { try { mCanvas = mHolder.lockCanvas(); //draw sth } catch (Exception e) { } finally { if (mCanvas != null) mHolder.unlockCanvasAndPost(mCanvas);//这里确保每次都能提交 } } @Override public void run() { if (isDrawing) { draw(); } }}说时迟,那时快,基本框架的代码已经撸完。毕竟作为LOL青铜段的大神,这手速,不谈了
那么现在就可以开始画啦:
首先,我们先把时钟的圆盘画出来,代码很简单:
mCanvas.drawColor(Color.WHITE);//注意一定要刷屏mPaint.setColor(Color.BLACK);mCanvas.drawCircle(getWidth() / 2, getHeight() / 2, mRadius, mPaint);
然后是画刻度和数字:
注意:这里画刻度和数字就需要捡回来高中的三角函数的数学了,作为曾经的数学课代表,so easy啦
弧度的图形表示:
求坐标点并修正坐标系的三角函数公式:
private float calculateX(int radius, double radian) { return (float) (radius * Math.cos(radian)) + mCenterX;}private float calculateY(int radius, double radian) { return -(float) (radius * Math.sin(radian)) + mCenterY;}
大体思想,我们先考虑,一个圆盘有60个小格,那么每个小格自然占的弧度是
public static final double= 2 * Math.PI / 60;
又由于我打算从12这个数字开始顺时针画一周,因此起始弧度为HALF_PI=Math.PI / 2;需要注意的是,我们的整点的格子会有数字并且刻度线会加粗处理,因此,我们用currentPosition来记录当前所画的是第几个刻度,每5的整倍数刻度线就会加粗加长处理(好羞涩)
/** * 画刻度和数字 */ private void drawScaleAndNum() { for (double i = HALF_PI; i > -1.5 * Math.PI; i -= intervalRadian) { currentPosition += 1; float outCircleX = calculateX(mRadius, i); float outCircleY = calculateY(mRadius, i);//弧度的Y轴和Android的Y轴方向相反,因此取反 float inCircleX;//从圆盘上的点画起,确定终点的位置圆,从而画刻度线 float intCircleY; if ((currentPosition - 1) / 5 < 12 && (currentPosition - 1) % 5 == 0) {//整点 inCircleX = calculateX(mRadius - DensityUtil.dip2px(mContext, 12.5f), i); intCircleY = calculateY(mRadius - DensityUtil.dip2px(mContext, 12.5f), i); int hourNum = (currentPosition - 1) / 5 == 0 ? 12 : (currentPosition - 1) / 5; drawNum(mCanvas, hourNum + "", calculateX(mRadius - DensityUtil.dip2px(mContext, 30), i), calculateY(mRadius - DensityUtil.dip2px(mContext, 30), i)); mPaint.setStrokeWidth(4);//整点的刻度线加粗 } else { inCircleX = calculateX(mRadius - DensityUtil.dip2px(mContext, 5), i); intCircleY = calculateY(mRadius - DensityUtil.dip2px(mContext, 5), i); mPaint.setStrokeWidth(2); } mCanvas.drawLine(outCircleX, outCircleY, inCircleX, intCircleY, mPaint); } currentPosition = 0; }画数字的方法:private void drawNum(Canvas canvas, String text, float textX, float textY) { mPaint.setTextSize(DensityUtil.dip2px(mContext, 12)); float textWidth = mPaint.measureText(text); canvas.drawText(text, textX - textWidth / 2, textY + DensityUtil.dip2px(mContext, 4), mPaint);//绘制数字并修正数字的位置 }
然后是画时,分,秒针:private void drawClockHand() { mCanvas.drawLine(mCenterX, mCenterY, calculateX(SecondHandLength, secondRadian + HALF_PI), calculateY(SecondHandLength, secondRadian + HALF_PI), mPaint); mPaint.setColor(Color.BLUE); mCanvas.drawLine(mCenterX, mCenterY, calculateX(MinuteHandLength, secondRadian / 60 + HALF_PI), calculateY(MinuteHandLength, secondRadian / 60 + HALF_PI), mPaint); mPaint.setColor(Color.RED); //注意,这里除以的是720不是3600,因为时针走一小格为12分钟,相当于分针走12格,秒针走720格 mCanvas.drawLine(mCenterX, mCenterY, calculateX(hourHandLength, secondRadian / 720 + HALF_PI), calculateY(hourHandLength, secondRadian / 720 + HALF_PI), mPaint); }
好啦,基本的轮廓已经画完:
我们让它跑起来吧:
在Run方法里面不断地更新当前时间:更新完之后,再进行绘制。并计算绘制用时,如果不足一秒,通过sleep让其睡眠,确保/** * 更新当前时间和刻度值 */private void updateCurrentTime() { mFormat.format(new Date()); mHour = mFormat.getCalendar().get(Calendar.HOUR_OF_DAY); mMinute = mFormat.getCalendar().get(Calendar.MINUTE); mSecond = mFormat.getCalendar().get(Calendar.SECOND); int totalS = mHour * 3600 + mMinute * 60 + mSecond; secondRadian = -totalS * intervalRadian;}我们每秒刷新一次。
@Overridepublic void run() { while (mIsDrawing && sizeChanged) { try { updateCurrentTime(); long drawBefore = System.currentTimeMillis(); draw(); long drawTime = System.currentTimeMillis() - drawBefore; if (drawTime < 1000) { Thread.sleep(1000 - drawTime); } } catch (Exception e) { e.printStackTrace(); } }}附上定义的成员变量:private SurfaceHolder mHolder; private Canvas mCanvas; private boolean mIsDrawing; private Paint mPaint; private int mRadius; private int currentPosition = 0;//记录目前所画第几个刻度点,从3点开始逆时针 private int mCenterX; private int mCenterY; private int hourHandLength; private int MinuteHandLength; private int SecondHandLength; private double secondRadian; private boolean sizeChanged; private int mMinute; private int mSecond; private int mHour; private SimpleDateFormat mFormat; public static final double intervalRadian = 2 * Math.PI / 60; private static final double HALF_PI = Math.PI / 2; private Context mContext;
至此,我们就大功告成啦。跑起来的效果就如开篇所示,有兴趣的朋友不妨试试O(∩_∩)O,第一次写博客,有不足的地方,欢迎指出交流学习附上项目源码地址:点击下载源码
- SurfaceView打造自定义时钟ClockView
- Android 自定义View(四) 时钟clockView
- Android自定义View实现时钟效果ClockView
- Android自定义ClockView实现时钟效果
- Android自定义控件之ClockView时钟效果
- ClockView 时钟
- ClockView时钟类
- android自定义ClockView
- android自定义ClockView
- 安卓开发 自定义控件 奥米噶 ClockView,打造自己的奥米噶送给你的女神
- Android自定义View—ClockView
- ClockView——简单的Android时钟控件
- SurfaceView实现模拟时钟
- 自定义surfaceview
- surfaceview自定义
- 自定义时钟
- 自定义时钟
- Android-ClockView
- 语义化的理解
- PHP Socket 编程过程详解
- thinkphp隐藏index.php/home,并允许访问其他模块
- 关于子类对象的构造函数和父类构造函数的执行顺序
- ROS:关于tf的探索(1) Writing a tf broadcaster(Python)
- SurfaceView打造自定义时钟ClockView
- Picasso使用
- 数据库3_最左前缀原则
- 支付系统的对账处理
- C Primer Plus学习 三十六 寄存器变量
- c语言基本类型和指针
- ace 打造后端管理框架 bootstrap mybaits spring
- 使用Android Studio2.2进行NDK编程在现有工程中添加JNI
- 图片上传 预览 及 获取base64