Android仪表盘实现自动增长的动画

原创 2017年01月03日 14:54:45

先看一下效果图
随着时间变化这里写图片描述这里写图片描述
随着时间的变化,圆弧增长的同时,圆弧顶点的圆球也跟着增长.

上代码,注释很详细:

自定义view类

public class CircleProgressView extends View {

    /**
     * 直径
     */
    private int mDiameter;

    /**
     * 绘制时控制绘制的范围
     */
    private Paint mPaint;
    private float progressValue = 0;
    RectF rect;

    public CircleProgressView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleProgressView(Context context) {
        this(context, null);
    }

    /**
     * 获得自定义的样式属性
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    public CircleProgressView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyle, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.CircleProgressView_diameter:
                    // 默认设置为40dp
                    mDiameter = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 40, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();

        mPaint = new Paint();
        rect = new RectF();
        progressValue = 0;
    }

    public void setProgressValue(float progressValue) {
        this.progressValue = progressValue;

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;
        int height = 0;

        //设置直径的最小值
        if (mDiameter <= 40) {
            mDiameter = 40;
        }
        height = mDiameter;
        width = mDiameter;

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int mWidth = getMeasuredWidth();//得到测量宽度
        int mHeight = getMeasuredHeight();//得到测量高度
        /************************************绘制圆弧***********************************/
        float section = progressValue / 100;//progressValue是传进来的值,由定时器不停地发送过来
        mPaint.setAntiAlias(true);//消除锯齿
        mPaint.setStrokeWidth((float) 11);//画笔宽度
        mPaint.setStyle(Style.STROKE);//描边
        mPaint.setStrokeCap(Cap.ROUND);//ROUND,表示是圆角的笔触
        rect.set(20, 20, mWidth - 20, mHeight - 20);//矩形区域,用来限制绘制的圆弧范围
        mPaint.setColor(Color.BLACK);
        /*
         颜色线性渐变
         LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,Shader.TileMode tile)
         float x0: 渐变起始点x坐标
         float y0:渐变起始点y坐标
         float x1:渐变结束点x坐标
         float y1:渐变结束点y坐标
         int color0: 起始渐变色
         int color1: 结束渐变色
         Shader.TileMode tile: CLAMP边缘拉伸
         */
        LinearGradient shader = new LinearGradient(3, 3, mWidth - 3, mHeight - 3, Color.parseColor("#4299ff"), Color.parseColor("#3cedff"), Shader.TileMode.CLAMP);
        mPaint.setShader(shader);
        //画弧,第一个参数是RectF,第二个参数是角度的开始,第三个参数是旋转多少度,第四个参数是true的时候画扇形,是false的时候画弧线
        canvas.drawArc(rect, 90, section * 360, false, mPaint);

        /************************************绘制小圆球***********************************/
        mPaint.setStyle(Style.FILL);//填充
        mPaint.setColor(Color.BLUE);
        float radius = rect.height() / 2;//半径
        //获取圆弧的圆心坐标
        PointF mCenterPoint = new PointF(rect.centerX(), rect.centerY());
        PointF mRunCirclePoint = new PointF();//小圆球的圆心坐标
        float a = section * 360 + 90;//小球圆心和圆弧圆心连线与x轴的夹角(顺时针旋转)
        if (a >= 90 && a < 180) {
            mRunCirclePoint.x = mCenterPoint.x - radius * (float) Math.sin((a - 90) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y + radius * (float) Math.cos((a - 90) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第三象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 180 && a < 270) {
            mRunCirclePoint.x = mCenterPoint.x - radius * (float) Math.cos((a - 180) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y - radius * (float) Math.sin((a - 180) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第四象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 270 && a < 360) {
            mRunCirclePoint.x = mCenterPoint.x + radius * (float) Math.sin((a - 270) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y - radius * (float) Math.cos((a - 270) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第一象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 360 && a <= 450) {
            mRunCirclePoint.x = mCenterPoint.x + radius * (float) Math.cos((a - 360) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y + radius * (float) Math.sin((a - 360) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第二象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        //绘制圆球,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象
        canvas.drawCircle(mRunCirclePoint.x, mRunCirclePoint.y, 10, mPaint);
    }

}

在布局XML文件中的使用方式:

<com.lhy.view.CircleProgressView
       android:id="@+id/circle_progress_view4"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       custom:diameter="180px" />

在资源文件values文件夹下的新增attr.xml添加如下代码:

    <attr name="diameter" format="dimension" />
    <declare-styleable name="CircleProgressView">
        <attr name="diameter" />
    </declare-styleable>

调用方式(主要代码):

private CircleProgressView circleProgressView4;
circleProgressView4 = (CircleProgressView) findViewById(R.id.circle_progress_view4);


// progressValue4 即为不断传入的值,从0开始,不断的自增长,直到和h(目标值)相等.
 private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
             if (msg.what == 4) {
                //空气湿度
                circleProgressView4.setProgressValue(progressValue4);//设置传入的值
                circleProgressView4.postInvalidate();
                progressValue4 += 0.1;
                if (progressValue4 > h) {// h 即为目标值(空气湿度)
                    task4.cancel();
                }
            }
        }
       return false;
 });
    TimerTask task4 = new TimerTask() {
        @Override
        public void run() {
            Message message = Message.obtain();
            message.what = 4;
            handler.sendMessage(message);
        }
    };
Timer timer = new Timer();
timer.schedule(task4, 1000, 10);

好了,代码已经贴完,下面继续上图(自己理解的小球运动轨迹公式):
这里写图片描述
对应的代码如下:

/************************************绘制小圆球***********************************/
        mPaint.setStyle(Style.FILL);//填充
        mPaint.setColor(Color.BLUE);
        float radius = rect.height() / 2;//半径
        //获取圆弧的圆心坐标
        PointF mCenterPoint = new PointF(rect.centerX(), rect.centerY());
        PointF mRunCirclePoint = new PointF();//小圆球的圆心坐标
        float a = section * 360 + 90;//小球圆心和圆弧圆心连线与x轴的夹角(顺时针旋转)
        if (a >= 90 && a < 180) {
            mRunCirclePoint.x = mCenterPoint.x - radius * (float) Math.sin((a - 90) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y + radius * (float) Math.cos((a - 90) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第三象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 180 && a < 270) {
            mRunCirclePoint.x = mCenterPoint.x - radius * (float) Math.cos((a - 180) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y - radius * (float) Math.sin((a - 180) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第四象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 270 && a < 360) {
            mRunCirclePoint.x = mCenterPoint.x + radius * (float) Math.sin((a - 270) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y - radius * (float) Math.cos((a - 270) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第一象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        if (a >= 360 && a <= 450) {
            mRunCirclePoint.x = mCenterPoint.x + radius * (float) Math.cos((a - 360) * (2 * Math.PI / 360));
            mRunCirclePoint.y = mCenterPoint.y + radius * (float) Math.sin((a - 360) * (2 * Math.PI / 360));
            Log.i("CircleProgressView", "第二象限: x=" + mRunCirclePoint.x + ",y=" + mRunCirclePoint.y);
        }
        //绘制圆球,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象
        canvas.drawCircle(mRunCirclePoint.x, mRunCirclePoint.y, 10, mPaint);

一句话概括: 开启一个定时器不断地传入一个自增长的值.
OK,全部搞定!

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Android仪表盘实现自动增长的动画

先看一下效果图 随着时间的变化,圆弧增长的同时,圆弧顶点的圆球也跟着增长.上代码,注释很详细:自定义view类public class CircleProgressView extends Vi...

Mongodb 自动增长 自增id 实现

1, 'step' => 1, ); $instance = new Mongo(); $instance =

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

Android自定义仪表盘

前几天项目中用到一个上阵指数大盘指数仪表图效果如下: 一开始觉得用自定义View来写这个界面,而且仪表盘的图片也给好了,本来想这会非常简单,结果因为指针也是一张图片,指针的圆心不好控制,在给数值的时...

WPF绚丽仪表盘动画

WPF绚丽仪表盘动画

Android 中最实用的动画效果实现

Animation动画效果的实现 博客分类:  android AndroidOPhone360QQXML  提供了三种动画效果:逐帧动画(frame-by-frame a...

九种原生js动画效果

在做页面中,多数情况下都会遇到页面上做动画效果,我们大部分做动画的时候都是使用框架来做(比如jquery),这里我介绍下如何让通过原生的js来实现像框架一样的动画效果! 1、匀速动画效果 说明:匀...

MongoDB学习笔记一 ID自增长

mongodb 自增长模式

仿支付宝“数字增长动画”

一、前言 一直都觉得支付宝的数字增长动画很有趣,今天抽空写了一个Demo与大家分享一下。 最终的实现效果图 二、使用方法 调用方法比较简单。有两个重载方法,第一个只需要传入一个结束值就行了。 ...

Android 自定义仪表盘

最近需要写一个用到各种图表的项目,比较过后决定用hellocharts框架,感觉足够简洁,后来发现这框架里没有仪表盘这个控件,但又不想换其他框架,于是在网上搜索一番,找到一个仪表盘学习demo,尝试后...

Android仪表盘

仪表盘,看到这个我无奈了, 老大说要用这个,网上找的他说都好难看   然后自己改额,改动第三方的源码,改了挺久 最后出来了这个效果 最后看到效果  发现改的值得了 ...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)