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可以做,不过比较复杂。换个思路,我们让美工提供一张背景图和一张橙色指针图(这里要注意了,一定要提供多种分辨率的图片,为适配不同分辨率的手机),给橙色指针一个旋转动画不就...

android:仪表盘(简单易实现)

开发的应用中需要实现一个仪表盘功能,上网找了一些代码,看起来有点麻烦,于是自己研究了一下,实现了这个仪表盘。 这个仪表盘的主要实现就在于以下这两张图片: 这两张图片其实是两个同心的正方形(周围都是...

Android自定义仪表盘View(汽车速度仪,刻度盘等),多种自定义模式,满足多种需求

效果图源码点我点我,欢迎star or fork

Android 打造形形色色的进度条 实现可以如此简单

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43371299 ,本文出自:【张鸿洋的博客】1、概述 最近需要用进度条,秉着不重复...

Android自定义控件—仿仪表盘进度控件ArcProgressBar

开门见山,效果图如下: 这种效果经常会遇到,但却一直不知道这个效果图应该怎么描述,所以暂且以“仪表盘进度控件”来描述,各位博友如果有更好的描述这种效果的词汇,请回复博文告诉我,在此先谢谢各位博友了!...

TextView 数字自动增长

就是一个TextView每个数子,不停的改变数值的书,在目标值停下来—直接上图(原谅我不会上传gif) 第一张(注意看标注) 第二张(注意看标注) 第三张(注意看标注,这里声明的te...

Android 仪表盘 图片 中心 旋转

因为项目需求,需要做一个基于仪表盘方式的数据显示方式,在网上一会 google,一会 baidu 最后得来的也就是对 Matrix 的几个解释,之前还被 hdpi,mdpi,ldip 搞得晕头转向的。...
  • zeus_9i
  • zeus_9i
  • 2011年12月27日 20:57
  • 14290

android 仪表盘控件

android 仪表盘控件,支持多分辨率,手绘UI,无需添加图片资源,支持刻度设置。 源码下载...

android 自定义View 仪表盘 DashboardView 的实现

有天上班,老板突然扔给我一张图,说:这个东西能不能做一下。我说应该可以。然后老板那就没有下文了,我想既然问了,那我就抽空做一下。当我做出来的时候去找老板,我说上次你给我发的那个图,我已经做出来了,您要...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android仪表盘实现自动增长的动画
举报原因:
原因补充:

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