天天看點

動态圓形進度條

動态圓形進度條

圓形旋轉進度條,外圓弧顔色漸變,内圓弧是兩張顔色不一樣圖案一樣的圖檔,要動态切割畫布切成一個圓弧形。

動态圓形進度條

在view裡實作圖檔疊加的效果有兩種方式,一是通過畫筆的paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN))方法去改變porterDuff.Mode的模式,PorterDuff圖檔疊加的模式有16種之多,有興趣自行學下。二是通過裁剪畫布canvas。

第一種方式

/**
     * 畫扇形圖檔 通過PorterDuff對圖檔進行裁剪
     * @param sourse
     * @param min
     * @return
     */
    public Bitmap drawArcBitmap(Bitmap sourse,int min){
        Paint paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
        canvas.drawArc(rectF,270,arcAngle,true,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(newArcBitmap,0,0,paint);
        return target;
    }
           

第二種方式

/**
     * 畫扇形圖檔 對畫布進行裁剪
     * @param canvas
     */
    public void drawArcBitmap(Canvas canvas,float rotAngle){
        canvas.save();
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Path path = new Path();
        RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
        int radius = (int)(width/2-rectF.left);
        float[] xyFloat = caclulatePoint(rotAngle,radius);
        path.moveTo(width/2,height/2);
        path.lineTo(width/2,rectF.top);
        if(arcAngle>=360){
            path.lineTo(width/2,rectF.top);
        }else{
            path.lineTo(xyFloat[0]+width/2,height/2 -xyFloat[1]);
        }

        path.addArc(rectF,startAngle,rotAngle);
        path.close();
        canvas.clipPath(path);
        canvas.drawBitmap(newArcBitmap,0,0,paint);
        canvas.restore();
    }
           

圓形背景

/**
     * 畫得到一個圓形的bitmap
     * @param sourse
     * @param min
     * @return
     */
    public Bitmap drawCircleBitmap(Bitmap sourse,int min){
        Paint paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        int radius = min/2-arcSize-arcSize/2;
        canvas.drawCircle(min/2,min/2,radius,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(sourse,0,0,paint);
        return target;
    }
           

在activity裡調用update方法,傳入參數就可以了。true代表動态,false為靜态顯示

circle_progress.update("65.6",true);
           

最後在view脫離視窗的時候調用onDetachedFromWindow系統方法回收bitmap

/**
     * 對bitmap進行回收
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if(bitmapBac!=null&&bitmapArc!=null&&newArcBitmap!=null&&newBitmapBac!=null){
            bitmapBac.recycle();
            bitmapBac = null;
            bitmapArc.recycle();
            bitmapArc = null;
            newArcBitmap.recycle();
            newArcBitmap = null;
            newBitmapBac.recycle();
            newBitmapBac = null;
        }
    }
           

完整代碼

/**
 * 
 */
public class MyProgressBar extends ProgressBar{
    public MyProgressBar(Context context) {
        super(context);
        init(context);
    }

    public MyProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    private Context context;
    private Paint paint,paintCircle,textPaints,bPaint;
    private int textWidth,textHeight;
    private int textSize = 80;//文字大小
    private int arcSize = 25;//圓弧寬度
    private int textColor = Color.GREEN;
    private float angle = 360;
    private int startAngle = 270;
    private String textPrecent="12%";
    private SweepGradient mColorShader;
    private int width,height;
    private Bitmap newBitmapBac,newArcBitmap;
    private int[] arcColorByte = new int[2];
    private float arcAngle;//圓弧旋轉的度數
    private StringBuffer sb = new StringBuffer();
    private int[] colorBytes = new int[101];
    private float[] positionBytes = new float[2];
    private RectF rectF  = new RectF();
    private String colorString = "#FF4D00";//漸變顔色透明度為0
    public void init(Context context){
        this.context = context;
        ColorBytes();
        //漸變圓弧相關
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(arcSize);
        //圓相關
        paintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
        paintCircle.setStyle(Paint.Style.STROKE);
        paintCircle.setStrokeWidth(arcSize);
        paint.setColor(Color.parseColor("#454545"));
        paintCircle.setAlpha(130);
        //文字相關
        textPaints = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaints.setColor(textColor);
        textPaints.setTextSize(textSize);
        //圓形bitmap相關
        bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bPaint.setDither(true);
        sb.append("%");
        bitmapBac = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_bac1);
        bitmapArc = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_bac2);
    }
    private Bitmap bitmapBac,bitmapArc;
    @Override
    protected synchronized void onDraw(Canvas canvas) {
        //畫圓形bitmap背景
        canvas.drawBitmap(drawCircleBitmap(newBitmapBac,width),0,0,bPaint);
        //畫扇形bitmap背景
        drawArcBitmap(canvas,activeAngle);
        //畫漸變圓和非漸變圓
        canvas.save();
        mColorShader = new SweepGradient(width/2-arcSize,height/2-arcSize,arcColorByte,null);
        Matrix matrix = new Matrix();
        matrix.setRotate(startAngle,width/2,height/2);
        canvas.setMatrix(matrix);
        paint.setShader(mColorShader);
        rectF = new RectF(arcSize,arcSize,width-arcSize,height-arcSize);
        canvas.drawArc(rectF,0,360,false,paintCircle);
        canvas.drawArc(rectF,0,activeAngle,false,paint);
        canvas.restore();
        //畫文字百分比
        //計算文字寬高
        Rect rect = new Rect();
        textPaints.getTextBounds(sb.toString(), 0, sb.toString().length(), rect);
        textWidth = rect.width();//文字寬
        textHeight = rect.height();//文字高
        int textX = width/2-textWidth/2;
        int textY = height/2+textHeight/2;
        canvas.drawText(sb.toString(),textX,textY,textPaints);

        PaintFlagsDrawFilter mSetfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
        canvas.setDrawFilter(mSetfil);
    }


    /**
     * 更新
     * @param sPrecent
     * @param isActive //true 為動态,false為靜态
     */
    private float activeAngle = 0;
    private float activePrecent = 0.0f;
    public void update(final String sPrecent,final boolean isActive){
        //int colorLength = colorBytes.length;
        //int newByteLength = (colorLength*arcAngle)/angle;
        try {
            double dPrecent = Double.parseDouble(sPrecent);
            if(dPrecent>100||dPrecent<0){
                return;
            }
            arcColorByte[0] = colorBytes[0];
            arcColorByte[1] = colorBytes[100];
            positionBytes[0] = 0.0f;
            positionBytes[1] = 1.0f;
            final int precent = (int)Math.round(dPrecent);
            arcAngle = (angle/101)*precent;//要旋轉的度數
            final float junmAngle = arcAngle/(float)precent;
            if(isActive){
                new Thread(){
                    @Override
                    public void run() {
                        while(isActive){
                            if(activePrecent>precent){
                                addStrBuffer(sPrecent);
                                activePrecent = arcAngle;
                                postInvalidate();
                                return;
                            }
                            addStrBuffer(activePrecent);
                            postInvalidate();
                            activeAngle+=junmAngle;
                            activePrecent++;
                            Log.e("precent","precent:"+activePrecent+"----------"+activeAngle);
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start();
            }else{
                addStrBuffer(sPrecent);
                activeAngle = arcAngle;
                invalidate();
            }
        }catch (Exception e){
            if(e instanceof ClassCastException){
                Toast.makeText(context,"必須是string類型的數字才有效",Toast.LENGTH_SHORT).show();
            }
            e.printStackTrace();
        }
    }

    public <T> void addStrBuffer(T precent){
        sb.setLength(0);
        sb.append(precent);
        sb.append("%");
    }

    /**
     * 系統onMeasure方法
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        //matrix.setScale((float) min/(float)sourse.getWidth(),(float)min/(float)sourse.getHeight());
        Matrix matrix = new Matrix();
        matrix.setScale((float) width/(float)bitmapBac.getWidth(),(float)height/(float)bitmapBac.getHeight());
        newBitmapBac = Bitmap.createBitmap(bitmapBac,0,0,bitmapBac.getWidth(),bitmapBac.getHeight(),matrix,true);
        newArcBitmap = Bitmap.createBitmap(bitmapArc,0,0,bitmapArc.getWidth(),bitmapArc.getHeight(),matrix,true);
    }
    /**
     * 畫得到一個圓形的bitmap
     * @param sourse
     * @param min
     * @return
     */
    public Bitmap drawCircleBitmap(Bitmap sourse,int min){
        Paint paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        int radius = min/2-arcSize-arcSize/2;
        canvas.drawCircle(min/2,min/2,radius,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(sourse,0,0,paint);
        return target;
    }

    /**
     * 畫扇形圖檔 通過PorterDuff對圖檔進行裁剪
     * @param sourse
     * @param min
     * @return
     */
    public Bitmap drawArcBitmap(Bitmap sourse,int min){
        Paint paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
        canvas.drawArc(rectF,270,arcAngle,true,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(newArcBitmap,0,0,paint);
        return target;
    }

    /**
     * 畫扇形圖檔 對畫布進行裁剪
     * @param canvas
     */
    public void drawArcBitmap(Canvas canvas,float rotAngle){
        canvas.save();
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Path path = new Path();
        RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
        int radius = (int)(width/2-rectF.left);
        float[] xyFloat = caclulatePoint(rotAngle,radius);
        path.moveTo(width/2,height/2);
        path.lineTo(width/2,rectF.top);
        if(arcAngle>=360){
            path.lineTo(width/2,rectF.top);
        }else{
            path.lineTo(xyFloat[0]+width/2,height/2 -xyFloat[1]);
        }

        path.addArc(rectF,startAngle,rotAngle);
        path.close();
        canvas.clipPath(path);
        canvas.drawBitmap(newArcBitmap,0,0,paint);
        canvas.restore();
    }

    /**
     * 擷取以圓心為軸的x,y坐标
     * @param angle
     * @param raduis
     * @return
     */
    private float[] floatsXY = new float[2];
    public float[] caclulatePoint(float angle,int raduis) {
        //Point point = new Point();
        double b = Math.toRadians(angle);
        double cos = Math.cos(b);
        double sin = Math.sin(b);
        double x = raduis * sin;
        double y = raduis * cos;
        //point.set((int) x, (int) y);
        floatsXY[0] = (float) x;
        floatsXY[1] = (float) y;
        return floatsXY;
    }

    /**
     * 得到一個漸變數組
     */
    public void ColorBytes(){
        //不直接用string的顔色值是統一換算成8位的顔色值以防止後邊截取字元串報錯
        int colorValue = Color.parseColor(colorString);
        String hex = Integer.toHexString(colorValue);
        Log.e(hex,"hex:"+hex);
        for (int i=0;i<colorBytes.length;i++){
            int f = 255-(int)(255*(1.0f - i/100.0f));
            String newHex = byteToHex(f)+hex.substring(2,8);
            BigInteger bi = new BigInteger(newHex, 16);
            int value = bi.intValue();
            colorBytes[i] = value;
            Log.e("value","value:"+newHex);
        }
    }
    private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
    public String byteToHex(int n) {
        if (n < 0) { n = n + 256; }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexArray[d1] + hexArray[d2];
    }

    /**
     * 對bitmap進行回收
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if(bitmapBac!=null&&bitmapArc!=null&&newArcBitmap!=null&&newBitmapBac!=null){
            bitmapBac.recycle();
            bitmapBac = null;
            bitmapArc.recycle();
            bitmapArc = null;
            newArcBitmap.recycle();
            newArcBitmap = null;
            newBitmapBac.recycle();
            newBitmapBac = null;
        }
    }
}