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

来源:互联网 发布:中文域名申请 编辑:程序博客网 时间:2024/05/20 18:19

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

上代码,注释很详细:

自定义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,全部搞定!

0 0