自定义ArcView-构造拓展性高的view

来源:互联网 发布:淘宝处方药购买步骤 编辑:程序博客网 时间:2024/05/03 05:14

这段时间用做一个飞行统计的模块,其中要做一个弧形展示效果,如图



做这个东西时,我们首先想到的是有没有现成的。于是就去github上找,找到了这个--https://github.com/lzyzsd/CircleProgress,大家有兴趣也可以去研究研究。本文参考的是其中的ArcProgress。其原理就是画弧和画字。。原理图:



先说画弧:

关键代码为:canvas.drawArc(rectF, startAngle, entityAngle, false, paint);
其中rectF为最外面的矩阵,startAngle为绘弧的开始角度,entityAngle为要画弧的最大值,false为不包含圆心,paint为画笔。

其次画字:

float bottomTextBaseline = getMeasuredHeight() - textPaint.descent();底部文字的基线
 canvas.drawText(bottomText, (getMeasuredWidth() - textPaint.measureText(bottomText)) / 2.0f, bottomTextBaseline, textPaint);

第一个参数为要画的文字,第二个参数为画字的起始x坐标,第三个为y坐标,第四个参数为文字画笔。

画字时的规则:参考http://blog.csdn.net/tianjf0514/article/details/7642656



接下来开始自定义我们的ArcView了,首先自定义属性,这个没什么可说的:

public ArcView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Arc);        this.radius = ta.getDimensionPixelSize(R.styleable.Arc_radius,0);        this.entityAngle = ta.getInt(R.styleable.Arc_entity_angle, DEFAULT_ENTITY_ANGLE);        this.initPercent = ta.getInt(R.styleable.Arc_init_percent,0);   //初始的百分值        init(context);    }

关键是测量我们的view的大小。一般来说,我们画的东西要在这个view可见范围内的中心。在onMeasure()方法中要计算出rectF(弧形的矩阵)。


上代码:

<pre name="code" class="java">protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        Log.e("arcView","onMeasure");        //整个内容的宽度        int contentWidth = (int) (radius * 2 + out_stroke_width);        //下面计算内容的高度        float halfTemp = out_stroke_width / 2;        float angle = (360 - entityAngle) / 2f;        arcBottom2CenterHeight = (float) (radius * Math.cos(angle / 180 * Math.PI));        int contentHeight = (int) (radius + arcBottom2CenterHeight + textPaint.descent() + out_stroke_width);        setMeasuredDimension(resolveSize(contentWidth,widthMeasureSpec),resolveSize(contentHeight,heightMeasureSpec));        float contentLeft,contentTop,contentRight,contentBottom;    //矩阵的左右上底        if(getMeasuredWidth() == contentWidth){            contentLeft = halfTemp;            contentRight = contentWidth - halfTemp;        }else{            contentLeft = (getMeasuredWidth() - contentWidth) / 2 + halfTemp;            contentRight = contentLeft + contentWidth - 2 * halfTemp;        }        if(getMeasuredHeight() == contentHeight){            contentTop = halfTemp;            contentBottom = contentWidth - halfTemp;        }else{            contentTop = (getMeasuredHeight() - contentHeight) / 2 + halfTemp;            contentBottom = contentTop + contentWidth - 2 * halfTemp;        }        rectF = new RectF(contentLeft,contentTop,contentRight,contentBottom);    }


接下来是ondraw方法:

protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        Log.e("arcView","draw"); //锁屏解锁后会再次调用ondraw()方法        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));        paint.setStrokeWidth(default_stroke_width);        paint.setColor(unfinishedStrokeColor);        canvas.drawArc(rectF, startAngle, entityAngle, false, paint);        paint.setStrokeWidth(out_stroke_width);        paint.setColor(finishedStrokeColor);        canvas.drawArc(rectF, startAngle, initSweepAngle, false, paint);        //画下面文字        textPaint.setTextSize(default_gray_text_size);        textPaint.setColor(default_gray_text_color);        float bottomTextBaseline = getMeasuredHeight() - textPaint.descent();        canvas.drawText(bottomText, (getMeasuredWidth() - textPaint.measureText(bottomText)) / 2.0f, bottomTextBaseline, textPaint);        //画上面文字        float topTextBaseline = radius / 2 + out_stroke_width / 2;        canvas.drawText(topText,(getMeasuredWidth() - textPaint.measureText(topText)) / 2.0f,topTextBaseline,textPaint);        //画中心文字        textPaint.setTextSize(default_percent_text_size);        textPaint.setColor(default_percent_text_color);        float centerTextBaseline = getMeasuredHeight() / 2 - textPaint.ascent() / 2;        canvas.drawText(centerText,(getMeasuredWidth() - textPaint.measureText(centerText)) / 2.0f,centerTextBaseline,textPaint);    }

手机锁屏后再亮屏,view的ondraw方法会调用,从下一个activity返回也会调用,结果是view可见是会调用ondraw()方法。

最后重写onSaveInstanceState和onRestoreInstanceState来保存和恢复数据

protected Parcelable onSaveInstanceState() {        Log.e("arcView","onSaveInstanceState");        Bundle bundle = new Bundle();        bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());        bundle.putFloat(INSTANCE_PROGRESS, initSweepAngle);        return bundle;    }    @Override    protected void onRestoreInstanceState(Parcelable state) {        Log.e("arcView","onRestoreInstanceState");        if(state instanceof Bundle) {            Bundle bundle = (Bundle) state;            initSweepAngle = bundle.getFloat(INSTANCE_PROGRESS,0);            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));            return;        }        super.onRestoreInstanceState(state);    }

我们有可能显示百分数时需要一个animate过程,上代码:

/*第一中方式实现animatePercent    private OverScroller scroller;    public void animatePercent(int percent){        if(scroller.isFinished()) {            scroller.startScroll(0, 0, percent, 0, 2000);//        scroller.fling(0,0,500,0,0,100,0,0);            invalidate();        }    }    @Override    public void computeScroll() {        if(scroller.computeScrollOffset()){            int tempPercent = scroller.getCurrX();            setPercent(tempPercent);        }        super.computeScroll();    }    */    private final int ANIMATE_DURATION = 1000;    private static final int SIXTY_FPS_INTERVAL = 1000 / 60;    private long mStartTime;    static final android.view.animation.Interpolator sInterpolator = new OvershootInterpolator();    public void animatePercent(final int percent){        mStartTime = System.currentTimeMillis();        this.post(new Runnable() {            @Override            public void run() {                float t = interpolate();                float currentPercent = 0 + t * percent;                setPercent(currentPercent);                if(t < 1){                    ArcView.this.postDelayed(this,SIXTY_FPS_INTERVAL);                }            }        });    }    private float interpolate() {        float t = 1f * (System.currentTimeMillis() - mStartTime) / ANIMATE_DURATION;        t = Math.min(1f,t);        return sInterpolator.getInterpolation(t);    }
第一种方式在结束时有点卡顿的现象,不知道你们的手机有没有。我推荐第二种,当然了,我们也可以用属性动画来实现。

最后是效果图



源码:

http://yunpan.cn/cdgSG2ii4CzKh (提取码:560b)





0 0
原创粉丝点击