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自定义View和属性动画完美结合,创造出酷炫圆环动画,带标尺和进度 无意中,在看了[【Android自定义View实战】之仿QQ运动步数圆弧及动画,Dylan计步中的控件StepAr...
  • u010785585
  • u010785585
  • 2016年11月15日 16:57
  • 3403

Android 仪表盘动画

思路:没错,我们用自定义View可以做,不过比较复杂。换个思路,我们让美工提供一张背景图和一张橙色指针图(这里要注意了,一定要提供多种分辨率的图片,为适配不同分辨率的手机),给橙色指针一个旋转动画不就...
  • hfrommane
  • hfrommane
  • 2017年02月12日 21:23
  • 575

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

效果图源码点我点我,欢迎star or fork
  • u013724061
  • u013724061
  • 2015年11月05日 11:24
  • 3575

android绘制动画实现方式

#代码用途 比如当我们想实现数据的走势,通过一个动画能够非常直观的表现出来,给用户一个好的体验。 以下代码通过动画巧妙的避免了通过线程来实现动画效果。(推荐) Value...
  • u013377714
  • u013377714
  • 2017年04月24日 14:53
  • 319

Android实现带动画效果的自定义View

准备工作: 考虑这个自定义view需要什么属性来方便在xml布局里面改。 在values/attrs.xml里面添加自定义属性...
  • qy1993qy
  • qy1993qy
  • 2016年10月15日 19:55
  • 386

iOS简单实现仪表盘进度动画

github链接 https://github.com/w463719052/ss.git
  • w463719052
  • w463719052
  • 2016年01月11日 11:40
  • 2246

安卓自定义View——(一:RaiseNumberAnimTextView 带数字增长动画的TextView)

1. 能自定义设置动画持续时长。 2. 能设置int型数字或float型数字。 3. 能控制动画速率,如匀速增加、加速、减速、先加速后减速等。 4. 能监听到动画正常的执行结束,调用后续方法。 ...
  • xiaoyu_93
  • xiaoyu_93
  • 2016年11月14日 14:56
  • 2403

Android 自定义View实现动态炫酷按钮

  • 2016年03月01日 17:11
  • 6.56MB
  • 下载

android简易时钟(animation的使用)

今天主要学习了一下动画的有关知识。参考书的内容特别有限,感觉讲的太过浅显,一共就两三页的样子,代码就占了大部分。。导致中间遇到了许多纠结的问题。。不过可能是对游戏开发知识的欠缺(因为每次都是用什么就学...
  • felicitia
  • felicitia
  • 2011年11月17日 23:01
  • 2237

WPF绚丽仪表盘动画

WPF绚丽仪表盘动画
  • yangyisen0713
  • yangyisen0713
  • 2014年01月13日 14:42
  • 6068
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android仪表盘实现自动增长的动画
举报原因:
原因补充:

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