查看原文
其他

高级UI特效—自定义一个精美的时钟就这么简单

2017-06-29 装糊涂的猪 终端研发部


前言介绍

一个优美的时钟特效

博客地址:

http://blog.csdn.net/androidstarjack/article/details/73824885

正文

今天我们来做一个高级UI特效—如何做一个精美的时钟特效。

话不多说,先上效果图:

当你认为上半屏很鬼畜的时候,它其实是个方向传感器。首先平放手机置于桌面,抬起手机左边缘,时钟向右倾斜,然后就是各个边缘倾斜的情况咯;至于下半屏,米粉应该知道是 MIUI系统的时钟。

在Android平台中,传感器框架通常是使用一个标准的三维坐标系来表示一个值的。

这个时候搞个官方的图装一波不过分吧:

方向传感器的学习,言简意赅,有示例代码

1.计算大小和位置 

由于 onSizeChanged 方法在构造方法、onMeasure 之后,又在 onDraw 之前,此时已经完成全局变量初始化,也得到了控件的宽高,所以可以在这个方法中确定一些与宽高有关的数值,比如这个 View 的 半径啊、padding值 等,方便绘制的时候计算大小和位置:

@Override    
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{        super.onSizeChanged(w, h, oldw, oldh);        //宽和高分别去掉padding值,取min的一半即表盘的半径        mRadius = Math.min(w - getPaddingLeft() - getPaddingRight(), h - getPaddingTop() - getPaddingBottom()) / 2;        mDefaultPadding = 0.12f * mRadius;//根据比例确定默认padding大小        mPaddingLeft = mDefaultPadding + w / 2 - mRadius + getPaddingLeft();        mPaddingTop = mDefaultPadding + h / 2 - mRadius + getPaddingTop();        mPaddingRight = mPaddingLeft;        mPaddingBottom = mPaddingTop;        mScaleLength = 0.12f * mRadius;//根据比例确定刻度线长度    }

2.绘制刻度 

然后开始绘制4个成3,6,9,12点方向的刻度线:

   /**     * 90度一个刻度线     */    private void drawScaleLines()    {        mScalePadding = 0.03f * mRadius;        mScaleLength = 0.13f * mRadius;        mCanvas.drawLine(mPaddingLeft+mCircleStrokeWidth + mScalePadding,getHeight() / 2 , mPaddingLeft + mCircleStrokeWidth + mScalePadding + mScaleLength, getHeight() / 2, mScaleLinePaint);        mCanvas.drawLine(getWidth() / 2,mPaddingTop + mCircleStrokeWidth + mScalePadding ,getWidth() / 2, mPaddingTop + mCircleStrokeWidth + mScalePadding + mScaleLength, mScaleLinePaint);        mCanvas.drawLine(getWidth() - mCircleStrokeWidth - mScalePadding -mScaleLength - mPaddingRight , getHeight() / 2 ,getWidth() - mCircleStrokeWidth - mScalePadding - mPaddingRight, getHeight() / 2, mScaleLinePaint);        mCanvas.drawLine(getWidth() / 2,getHeight()- mCircleStrokeWidth - mScalePadding -mScaleLength -mPaddingBottom ,getWidth() / 2, getHeight() - mCircleStrokeWidth - mScalePadding - mPaddingBottom, mScaleLinePaint);    }

3计算角度 

根据不断变化的秒针角度旋转画布,自己要计算出缺口圆弧的角度: 关键方法: mSecondHandPath.arcTo(mCircleRectF,-87,354)

private void drawSecondHand() {        mCanvas.save();        mCanvas.rotate(mSecondDegree, getWidth() / 2, getHeight() / 2);        mSecondHandPath.reset();        mCircleRectF.set(mPaddingLeft,mPaddingTop,getWidth()-mPaddingRight,getHeight()-mPaddingBottom);        mSecondHandPath.arcTo(mCircleRectF,-87,354);        mSecondHandPaint.setStyle(Paint.Style.STROKE);        mSecondHandPaint.setStrokeWidth(mCircleStrokeWidth);        mCanvas.drawPath(mSecondHandPath, mSecondHandPaint);        mCircleRectF.set(getWidth() / 2 - mCircleStrokeWidth,mPaddingTop-mCircleStrokeWidth,getWidth() / 2  + mCircleStrokeWidth ,mPaddingTop + mCircleStrokeWidth);        mSecondHandPaint.setStyle(Paint.Style.FILL);        mCanvas.drawArc(mCircleRectF, 0, 360, false, mSecondHandPaint);        mCanvas.restore();    }

4.画时针和分针 

时针和分针类似,针头为圆弧状,那么就用二阶贝赛尔曲线,路径为: moveTo( A),lineTo(B),quadTo(C,D),lineTo(E),close.

private void drawHourHand() {        mCanvas.save();        mCanvas.rotate(mHourDegree, getWidth() / 2, getHeight() / 2);        mHourHandPath.reset();        float offset = mPaddingTop ;        mHourHandPath.moveTo(getWidth() / 2 - 0.008f * mRadius, getHeight() / 2 - 0.01f * mRadius);        mHourHandPath.lineTo(getWidth() / 2 - 0.007f * mRadius, offset + 0.4f * mRadius);        mHourHandPath.quadTo(getWidth() / 2, offset + 0.38f * mRadius, getWidth() / 2 + 0.007f * mRadius, offset + 0.4f * mRadius);        mHourHandPath.lineTo(getWidth() / 2 + 0.008f * mRadius, getHeight() / 2 - 0.02f * mRadius);        mHourHandPath.close();        mHourHandPaint.setStyle(Paint.Style.FILL);        mCanvas.drawPath(mHourHandPath, mHourHandPaint);        mCircleRectF.set(getWidth() / 2 - 0.02f * mRadius, getHeight() / 2 - 0.02f * mRadius, getWidth() / 2 + 0.02f * mRadius, getHeight() / 2 + 0.02f * mRadius);        mCanvas.drawArc(mCircleRectF, 0, 360, false, mHourHandPaint);        mCanvas.restore();    }

5.画path  

最后由于path是close的,所以干脆画两个圆盖在上面

mCircleRectF.set(getWidth() / 2 - 0.02f * mRadius, getHeight() / 2 - 0.02f * mRadius,          getWidth() / 2 + 0.02f * mRadius, getHeight() / 2 + 0.02f * mRadius);          mCanvas.drawArc(mCircleRectF, 0, 360, false, mHourHandPaint);

6.计算传感器

辣么接下来就是如何实现方向传感器了 在构造函数中注册传感器:

sManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
mSensorOrientation = sManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
sManager.registerListener(this, mSensorOrientation SensorManager.SENSOR_DELAY_UI);

并实现SensorEventListener接口

@Overridepublic void onSensorChanged(SensorEvent sensorEvent) {    int
tbValue = (Math.round(sensorEvent.values[1]));    int
lrValue = (Math.round(sensorEvent.values[2]));    offsetTopAndBottom(tempTBValue - tbValue);    offsetLeftAndRight(tempLRValue - lrValue);    tempTBValue = tbValue;    tempLRValue = lrValue; }

OVER!

鲁迅说:Don't bb ,show me the code!

源码地址:

https://github.com/ftc300/AwesomeClock

博客地址:

https://ftc300.github.io/

http://www.jianshu.com/p/056aa0485913


终端研发部提倡: 没有做不到的,只有想不到的。

在这里获得的不仅仅是技术! 


让心,在阳光下学会舞蹈

让灵魂,在痛苦中学会微笑

—终端研发部—



如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809   

微信公众号:终端研发部


            

这里学到的不仅仅是技术


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存