Android 自定义View实现动画时钟 该项目使用AS开发,通过获取当前系统时间,然后通过自定义View加自定义的属性动画实现了一个动画时钟,对学习自定义View是一个很好的例子 目录 之前项目有个需求是在桌面上增加一个桌面时钟,当时是参考别人的博客,在其基础上添加了属性动画然后实现的。因此今天特地重新写了一遍这个自定义view 加深印象并出来 用手机拍的视频,然后转为GIF的,因为是试用的,所以就是这个渣渣效果,还有水印,求推荐一个好用的格式转换工具 为了编写方便,这里没有用到自定义属性,有需要的话,可以自行添加自定义属性,同时在代码中注释很详细,文章这里只简单介绍一下 这里各种new操作不要放在Ondraw方法中,避免重复实现 首先获取并计算宽高,设置各指针长度以及外圆的半径 借用一下别人的图 这里判断是否是第一次显示时钟,等于true为第一次,然后绘制标题,位置的计算根据上图 然后绘制刻度,圆盘 最后是绘制三个指针 绘制指针上的圆心点 第一次出现时不转动指针 在View中添加一个公共方法给外部调用 有时不需要执行动画的话,可以再添加一个公共方法直接设置first 为false //然后在布局添加自定义view即可 在Activity中使用ClockView并根据需求调用对应的方法 到这里文章就结束了,觉得还算可以的,欢迎啊
前言
效果图
项目实现
用到的属性
private Paint hPaint ,mPaint ,sPaint ,circlePaint ,cPointPaint,paintDegree,txtPaint,titlePaint; private final int maxWidth = 400; int width ,height; int hSound = 0; int mSound = 0; int sSound = 0; private int hcount = 0;//当前小时数 private int mcount = 0;//当前分钟数 private int scount = 0;//当前秒钟数 private final int hScale = 30;//每小时之间30度 private static final int mScale = 6;//每分钟之间是6度 RectF hRect , mRect ,sRect ;//三个 boolean first = true;//执行动画之后再转动指针
重写三个构造方法
public ClockView(Context context) { super(context); init(); } public ClockView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ClockView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); }
初始化各个指针的画笔,指针的矩形
private void init(){ //外圆盘画笔 circlePaint = new Paint(); circlePaint.setAntiAlias(true); circlePaint.setDither(true); circlePaint.setStyle(Paint.Style.STROKE); circlePaint.setColor(Color.BLACK); circlePaint.setStrokeWidth(1); //圆心画笔 cPointPaint = new Paint(); cPointPaint.setAntiAlias(true); cPointPaint.setDither(true); cPointPaint.setStyle(Paint.Style.FILL_AND_STROKE); cPointPaint.setColor(0xff4CAF50);//绿色 cPointPaint.setStrokeWidth(2); //时针画笔 hPaint = new Paint(); hPaint.setAntiAlias(true); hPaint.setDither(true); hPaint.setStyle(Paint.Style.FILL_AND_STROKE); hPaint.setColor(0xff349CE2);//蓝色 hPaint.setStrokeWidth(7); //时针矩形 hRect = new RectF(-16,0,89,0); //分针画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setColor(0xffDB2540);//红色 mPaint.setStrokeWidth(6); //分针矩形 mRect = new RectF(-25,0,140,0); //秒针画笔 sPaint = new Paint(); sPaint.setAntiAlias(true); sPaint.setDither(true); sPaint.setStyle(Paint.Style.FILL_AND_STROKE); sPaint.setColor(0xff4CAF50);//绿色 sPaint.setStrokeWidth(5); //秒钟矩形 sRect = new RectF(-30,0,180,0); //刻度画笔 paintDegree = new Paint(); paintDegree.setColor(0xff000000); paintDegree.setStyle(Paint.Style.STROKE); paintDegree.setAntiAlias(true); //文字画笔 txtPaint = new Paint(); txtPaint.setColor(0xff000000); txtPaint.setTextSize(20); txtPaint.setAntiAlias(true); //标题画笔 titlePaint = new Paint(); titlePaint.setColor(0xff000000); titlePaint.setTextSize(45); titlePaint.setAntiAlias(true); }
重写 onMeasure方法
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.AT_MOST && heightMode ==MeasureSpec.AT_MOST){ setMeasuredDimension(maxWidth,maxWidth); }else if (widthMode == MeasureSpec.AT_MOST ){ setMeasuredDimension(maxWidth,width); }else if (heightMode ==MeasureSpec.AT_MOST ){ setMeasuredDimension(height,maxWidth); } }
获取系统的时间
private void getDatas() { SimpleDateFormat format = new SimpleDateFormat("HH,mm,ss"); String time = format.format(new Date()); try { String s[] = time.split(","); hcount = Integer.parseInt(s[0]); mcount = Integer.parseInt(s[1]); scount = Integer.parseInt(s[2]); } catch (Exception ex) { ex.printStackTrace(); } }
重写ondraw方法
super.onDraw(canvas); width = getMeasuredWidth()-getPaddingStart()-getPaddingEnd(); height = getMeasuredHeight()-getPaddingBottom()-getPaddingTop(); width = height = Math.min(width,height); //圆心点 int cpoints = width/2; hSound = width/8;//时针长度 mSound = width/6;//分针长度 sSound = width/4;//秒针长度 int radius =cpoints*3/4;//外圆半径
if(!first){ getDatas(); } String titleText = "三原色时钟"; //X坐标等于圆心的X坐标减去文字的一半的长度,Y坐标等于圆心的Y坐标减圆的半径再减20 canvas.drawText(titleText,cpoints - titlePaint.measureText(titleText) / 2 ,cpoints-radius-20,titlePaint);
//画出12个小时的刻度线及文字 for (int i = 0; i < 12; i++) { String txtTime = Integer.toString(i); //3,6,9,12比其他的略粗略长 if(i%3==0) { if (i==0){ txtTime = "12"; } paintDegree.setStrokeWidth(5); canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 20, paintDegree); }else{ paintDegree.setStrokeWidth(4); canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 15, paintDegree); } canvas.drawText(txtTime,cpoints - txtPaint.measureText(txtTime) / 2,height / 2 - radius + 40,txtPaint); canvas.rotate(hScale, width / 2, height / 2); } //画出60个分钟的刻度线 for (int x = 0; x < 60; x++) { paintDegree.setStrokeWidth(3); if (x % 5 != 0) {//当x % 5 == 0时即是时钟刻度,因此不需要绘制,避免重复绘制 canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 8, paintDegree); } canvas.rotate(mScale, width / 2, height / 2); } //画外层圆 canvas.drawCircle(cpoints,cpoints,radius,circlePaint); //画内层圆 canvas.drawCircle(cpoints,cpoints,radius/6,circlePaint); //平移至中心点 canvas.translate(cpoints,cpoints); //保存画布 canvas.save();
//int hRotate = 270 + hScale * hcount; int offset = 30 * mcount / 60; offset -= offset % mScale;//时针相对分针数,有一个偏移量 int hRotate = 270 + hScale * hcount + offset; canvas.rotate(hRotate); // canvas.drawLine(0, -10, 0, hSound, hPaint);//画时针 canvas.drawRoundRect(hRect,15,15,hPaint);//画时针 canvas.restore(); canvas.save(); int mRotate = 270 + mScale * mcount ; canvas.rotate(mRotate); canvas.drawRoundRect(mRect,25,25,mPaint);//画分针 //canvas.drawLine(0, -15, 0, mSound, mPaint);//画分针 canvas.restore(); canvas.save(); //一圈360度,总共60秒,因此时间每多一秒,度数加6 int sRotate = 270 + mScale * scount ; canvas.rotate(sRotate); //canvas.drawLine(0, -25, 0, sSound, sPaint);//画秒针 canvas.drawRoundRect(sRect,15,15,sPaint);//画秒针
canvas.drawCircle(0,0,6,cPointPaint);//画圆心
if(!first){ postInvalidateDelayed(1000); }
最后给时钟添加上属性动画
public void startAnim(){ getDatas(); final ValueAnimator animatorh = ValueAnimator.ofInt(0,hcount>12?hcount-12:hcount);//大于十二点时减去12 避免转两圈 final ValueAnimator animatorm=ValueAnimator.ofInt(0,mcount); final ValueAnimator animators=ValueAnimator.ofInt(0,scount); //设置动画时长 animatorh.setDuration(1500); animatorm.setDuration(1500); animators.setDuration(1500); animatorh.setInterpolator(new LinearInterpolator()); animatorh.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { hcount = (int)animation.getAnimatedValue(); } }); animatorh.start(); animatorm.setInterpolator(new LinearInterpolator()); animatorm.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mcount = (int)animation.getAnimatedValue(); } }); animatorm.start(); animators.setInterpolator(new LinearInterpolator()); animators.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scount = (int)animation.getAnimatedValue(); postInvalidate();//添加之后动画才会执行,不然看不到效果 } }); animators.start(); //添加动画完成时的监听,在动画完成之后开始指针的转动 animators.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { first = false ; postInvalidate(); } }); }
public void SetFirstInit(Boolean ttt) { first =ttt; }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算