高级UI特效—自定义一个精美的时钟就这么简单
一个优美的时钟特效
正文博客地址:
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
终端研发部提倡: 没有做不到的,只有想不到的。
在这里获得的不仅仅是技术!
这里学到的不仅仅是技术