自定义控件Android知识程序员

时钟骚起来真没你啥事

2017-04-13  本文已影响216人  ftc300_carl

本文属于装糊涂的猪原创,转载请注明出处作者
文中的Demo地址位于:https://github.com/ftc300

话不多说,先上效果图:

clock.gif
当你认为上半屏很鬼畜的时候,它其实是个方向传感器。首先平放手机置于桌面,抬起手机左边缘,时钟向右倾斜,然后就是各个边缘倾斜的情况咯;至于下半屏,米粉应该知道是 MIUI系统的时钟。。
在Android平台中,传感器框架通常是使用一个标准的三维坐标系来表示一个值的。
这个时候搞个官方的图装一波不过分吧:
坐标系.jpg
方向传感器的学习,言简意赅,有示例代码

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是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);
表心.png

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

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

并实现SensorEventListener接口

    @Override
    public 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!


鲁迅.jpg

源码地址:https://github.com/ftc300/AwesomeClock
同时以后我会定期更新我的博客到我的网址,欢迎光顾:https://ftc300.github.io/

维护个公众号试试吧.png
上一篇下一篇

猜你喜欢

热点阅读