前一阵子看到了一块概念腕表,感觉非常有意思,就想能不能写一个在android手机上运行一下。本文地址:http://blog.csdn.net/qq_24505485/article/details/52717381
Hop Picker 的创意腕表
先上效果图:
原理分析:和原作者实现的不一样,作者给的原理图是将刻度围绕黄色线条圈起的地方分布的,而我实现的时候是按照蓝色线圈内去分布刻度的。这样刻度分布不会非常密集,而且从实现上更简单。如何确定蓝色区域圆的圆心和半径呢?
1.以实心圆的圆心为坐标轴原点2.设实心圆半径为 r ,设红色圆圈半径为R,有刻度的圆的半径为arcR。3.大圆和红色圆的交点是(-R,0)和(R,0),大圆过实心圆直径3/4处,交点为(0,-r/2),这些交点是我根据作者原理图大致定的。(你也可以定义这些点的位置)4.已知r,R,三个交点,求arcR的值和带有刻度圆的圆心位置。(求好之后才能绘图)arcR和圆心求解过程:
得到公式
求解得到acrR即可。
整个自定义view的代码如下:
本文地址: http://blog.csdn.net/qq_24505485/article/details/52717381public class HopPickerWatchView2 extends View { //控件实际的宽高,在onmeasure种获取 private int viewWidth = 0; private int viewHeight = 0; private Paint mPaint = new Paint(); //外圆画笔 private Paint outPaint = new Paint(); //刻度数,每一个刻度表示10min private int Scale = 72; //每一个刻度所占的角度 private float degree = 360f / Scale; //旋转角度 private float RotateDegree = 0; //每分钟度数 转一圈是12小时 // 360 / (12*60) = 0.5 private float perMinDegree = 0.5f; //以下7个属性的实际值还要在onmeasure重新测量 //表盘半径 private float r = 300; //外圆半径 private float R = 350; //刻度圆半径 假定那个圆弧 过外圆半圆处点和表盘直径3/4处点 推算得出 private float arcR = R * R / r + r / 4; //一小时间隔刻度线的长度 private float hourLen = 60; //半小时间隔刻度线的长度 private float halfHourLen = 45; //10min间隔刻度线的长度 private float tenMinLen = 15; //刻度数字位置,在一小时刻度的下方 private float numPosition = hourLen + 40; //watchface color private int DialColor = 0xFFE5E6EB; //black private int Black = 0xFF000000; //刻度圆路径 private Path arcPath;//= new Path(); //要扣的表盘 private Path watchface;//= new Path(); //刻度数字 private String nums[] = {"12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}; // 抠图抗锯齿 private PaintFlagsDrawFilter pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private void initMy() {//初始化画笔 mPaint.setAntiAlias(true); mPaint.setColor(DialColor); outPaint.setAntiAlias(true); outPaint.setStyle(Paint.Style.STROKE); } private void initOnMeasure() {//跟屏幕尺寸相关的初始化操作放到这个函数里 //初始化一些基本尺寸 // BoundsRadius = Math.min(viewWidth, viewHeight) / 2; r = Math.min(viewWidth, viewHeight) / 2; R = Math.min(viewWidth, viewHeight) / 2 + 50; arcR = R * R / r + r / 4; //初始化和尺寸相关的其他参数 // TODO: 2016/10/1 画笔宽度和刻度长度最好由dp换算,这样不同dpi的手机看到的指针和表盘线条粗细是一样的 outPaint.setStrokeWidth(5); outPaint.setTextSize(50); hourLen = 60; halfHourLen = 45; tenMinLen = 15; numPosition = hourLen +40; //onMeasure方法会被调用好几次,所以path.add方法 会 一直放入好几个 path //每次 直接new一个新的在add,就不会出现绘图的时候出现很多半径不同的圆了 arcPath = new Path(); arcPath.addCircle(0f, arcR - r / 2, arcR, Path.Direction.CW); watchface = new Path(); watchface.addCircle(0f, 0f, r, Path.Direction.CW); } public HopPickerWatchView2(Context context, AttributeSet attrs) { super(context, attrs); initMy(); } public HopPickerWatchView2(Context context) { super(context); initMy(); } public HopPickerWatchView2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initMy(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //初始化坐标系,以view中心点为坐标原点,方便后续计算 canvas.translate(viewWidth / 2, viewHeight / 2); //先画表盘 canvas.drawCircle(0, 0, r, mPaint); //设置抗锯齿,不设置,扣出来的圆有明显锯齿 canvas.setDrawFilter(pfdf); //抠圆 canvas.clipPath(watchface); //开始旋转,每次旋转的角度由时间决定 setRotateDegree(); canvas.rotate(RotateDegree); //画刻度圆的画笔设置成黑色 outPaint.setColor(Black); //绘制刻度圆 canvas.drawPath(arcPath, outPaint); //绘制刻度 canvas.save(); //将坐标原点移动到刻度圆的圆心处 canvas.translate(0, arcR - r / 2); //反向旋转刻度圆,使其一直保持相对水平 canvas.rotate(-RotateDegree); for (int i = 0; i < Scale; i++) { if (i % 6 == 0) {//带数字的大刻度 canvas.drawLine(0, arcR, 0, arcR - hourLen, outPaint); //开始绘制数字 canvas.save(); //位移画布,是数字绘制在刻度圆内,与刻度的距离可自行定义 canvas.translate(0, numPosition - arcR); //纠正 数字旋转的角度 使表盘上的数字一直是正对我们的 canvas.rotate(-i / 6 * 30); //绘制数字,并保证数字正对刻度线 canvas.drawText(nums[i / 6], -outPaint.measureText(nums[i / 6]) / 2, 0, outPaint); canvas.restore(); } else if (i % 6 == 3) {//间隔半小时的中刻度 canvas.drawLine(0, arcR, 0, arcR - halfHourLen, outPaint); } else {//间隔10min的小刻度 canvas.drawLine(0, arcR, 0, arcR - tenMinLen, outPaint); } //旋转 加偏移量,绘制下一条刻度线 canvas.rotate(degree); } canvas.restore(); //最后绘制指针 #F87219橘黄色 outPaint.setColor(0xFFF87219); canvas.drawLine(0, -r, 0, r, outPaint); outPaint.setColor(Black);//恢复黑色 postInvalidateDelayed(1000);//每秒刷新一次 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); viewWidth = MeasureSpec.getSize(widthMeasureSpec); viewHeight = MeasureSpec.getSize(heightMeasureSpec); initOnMeasure(); setMeasuredDimension(viewWidth, viewHeight); } //根据当前时间设置画布旋转角度 private void setRotateDegree() { Calendar calendar = Calendar.getInstance(); int Hour = calendar.get(Calendar.HOUR); int Min = calendar.get(Calendar.MINUTE); RotateDegree = (Hour * 60 + Min) * perMinDegree; } }