Android 自定義View修煉-高仿獵豹清理大師自定義內存開口圓環比例進度View

1、概述html

看見獵豹清理大師的內存開口圓環比例進度 挺有意思的,因而就是想本身實現下這樣的效果,因而反編譯了獵豹清理canvas

大師的app看了下,原來是有兩張圖,因而腦子裏就過了下思路,利用上下兩張圖,旋轉上面張圖以及使用安全

PorterDuffXfermode  來設置合適的渲染模式,就能夠達到效果。下面看看我們的效果吧app

2、效果圖ide

3、Xfermode渲染模式簡介:post

xfermode影響在Canvas已經有的圖像上繪製新的顏色的方式 
* 正常的狀況下,在圖像上繪製新的形狀,若是新的Paint不是透明的,那麼會遮擋下面的顏色. 
* 若是新的Paint是透明的,那麼會被染成下面的顏色 

下面的Xfermode子類能夠改變這種行爲: 

AvoidXfermode  指定了一個顏色和容差,強制Paint避免在它上面繪圖(或者只在它上面繪圖)。 

PixelXorXfermode  當覆蓋已有的顏色時,應用一個簡單的像素XOR操做。 

PorterDuffXfermode  這是一個很是強大的轉換模式,使用它,可使用圖像合成的16條Porter-Duff規則的任意一條來控制Paint如何與已有的Canvas圖像進行交互。字體

這裏不得不提到那個經典的圖:this

上面的16種模式的說明以下:spa

從上面咱們能夠看到PorterDuff.Mode爲枚舉類,一共有16個枚舉值:.net

1.PorterDuff.Mode.CLEAR  

  所繪製不會提交到畫布上。
2.PorterDuff.Mode.SRC

   顯示上層繪製圖片
3.PorterDuff.Mode.DST

  顯示下層繪製圖片
4.PorterDuff.Mode.SRC_OVER

  正常繪製顯示,上下層繪製疊蓋。
5.PorterDuff.Mode.DST_OVER

  上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN

   取兩層繪製交集。顯示上層。
7.PorterDuff.Mode.DST_IN

  取兩層繪製交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT

 取上層繪製非交集部分。
9.PorterDuff.Mode.DST_OUT

 取下層繪製非交集部分。
10.PorterDuff.Mode.SRC_ATOP

 取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP

 取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR

  異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN

  取兩圖層所有區域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN

  取兩圖層所有,點亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY

  取兩圖層交集部分疊加後顏色
16.PorterDuff.Mode.SCREEN

  取兩圖層所有區域,交集部分變爲透明色

 

4、自定義開口圓環View的實現

一、初始化繪製所需的畫筆,字體顏色、大小等變量

public XCArcProgressBar(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
        
        
        degrees =  0;
        paint  =  new Paint();
        //從attrs.xml中獲取自定義屬性和默認值
        TypedArray typedArray  = context.obtainStyledAttributes(attrs, R.styleable.XCRoundProgressBar);
        textColor  =typedArray.getColor(R.styleable.XCRoundProgressBar_textColor, Color.RED);
        textSize = typedArray.getDimension(R.styleable.XCRoundProgressBar_textSize, 15);
        max = typedArray.getInteger(R.styleable.XCRoundProgressBar_max, 100);
        isDisplayText  =typedArray.getBoolean(R.styleable.XCRoundProgressBar_textIsDisplayable, true);
        typedArray.recycle();
        
    }

二、在onDraw()中繪製出來

在onDraw()方法中利用PorterDuffXfermode渲染模式繪製兩張開口圓環Bitmap,並計算前景圖的旋轉角度,從而達到效果圖效果。

首先先繪製底部背景圖,而後繪製進度前景圖,最後利用PorterDuffXfermode的渲染模式和旋轉角度比例來進行前景圖和背景圖的遮罩處理。

@Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        int centerX = getWidth() / 2;// 獲取中心點X座標
        int centerY = getHeight() / 2;// 獲取中心點Y座標

        Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        Canvas can = new Canvas(bitmap);
        // 繪製底部背景圖
        bmpTemp = Utils.decodeCustomRes(getContext(), R.drawable.arc_bg);
        float dstWidth = (float) width;
        float dstHeight = (float) height;
        int srcWidth = bmpTemp.getWidth();
        int srcHeight = bmpTemp.getHeight();

        can.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                | Paint.FILTER_BITMAP_FLAG));// 抗鋸齒

        Bitmap bmpBg = Bitmap.createScaledBitmap(bmpTemp, width, height, true);
        can.drawBitmap(bmpBg, 0, 0, null);

        // 繪製進度前景圖
        Matrix matrixProgress = new Matrix();
        matrixProgress.postScale(dstWidth / srcWidth, dstHeight / srcWidth);
        bmpTemp = Utils.decodeCustomRes(getContext(), R.drawable.arc_progress);

        Bitmap bmpProgress = Bitmap.createBitmap(bmpTemp, 0, 0, srcWidth,
                srcHeight, matrixProgress, true);
        degrees = progress * 270 / max - 270;
        //遮罩處理前景圖和背景圖
        can.save();
        can.rotate(degrees, centerX, centerY);
        paint.setAntiAlias(true);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
        can.drawBitmap(bmpProgress, 0, 0, paint);
        can.restore();
        
        if ((-degrees) >= 85) {
            int posX = 0;
            int posY = 0;
            if ((-degrees) >= 270) {
                posX = 0;
                posY = 0;
            } else if ((-degrees) >= 225) {
                posX = centerX / 2;
                posY = 0;
            } else if ((-degrees) >= 180) {
                posX = centerX;
                posY = 0;
            } else if ((-degrees) >= 135) {
                posX = centerX;
                posY = 0;
            } else if ((-degrees) >= 85) {
                posX = centerX;
                posY = centerY;
            }
            
            if ((-degrees) >= 225) {

                can.save();
                Bitmap dst = bitmap
                        .createBitmap(bitmap, 0, 0, centerX, centerX);
                paint.setAntiAlias(true);
                paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                Bitmap src = bmpBg.createBitmap(bmpBg, 0, 0, centerX, centerX);
                can.drawBitmap(src, 0, 0, paint);
                can.restore();

                can.save();
                dst = bitmap.createBitmap(bitmap, centerX, 0, centerX, height);
                paint.setAntiAlias(true);
                paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                src = bmpBg.createBitmap(bmpBg, centerX, 0, centerX, height);
                can.drawBitmap(src, centerX, 0, paint);
                can.restore();

            } else {
                can.save();
                Bitmap dst = bitmap.createBitmap(bitmap, posX, posY, width
                        - posX, height - posY);
                paint.setAntiAlias(true);
                paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
                Bitmap src = bmpBg.createBitmap(bmpBg, posX, posY,
                        width - posX, height - posY);
                can.drawBitmap(src, posX, posY, paint);
                can.restore();
            }
        }
        //繪製遮罩層位圖
        canvas.drawBitmap(bitmap, 0, 0, null);
        
        // 畫中間進度百分比字符串
        paint.reset();
        paint.setStrokeWidth(0);
        paint.setColor(textColor);
        paint.setTextSize(textSize);
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        int percent = (int) (((float) progress / (float) max) * 100);// 計算百分比
        float textWidth = paint.measureText(percent + "%");// 測量字體寬度,須要居中顯示

        if (isDisplayText && percent != 0) {
            canvas.drawText(percent + "%", centerX - textWidth / 2, centerX
                    + textSize / 2 - 25, paint);
        }
        //畫底部開口處標題文字
        paint.setTextSize(textSize/2);
        textWidth = paint.measureText(title);
        canvas.drawText(title, centerX-textWidth/2, height-textSize/2, paint);
    }

三、設置比例進度的同步接口方法,主要供刷新進度比例用。

/**
     * 設置進度,此爲線程安全控件,因爲考慮多線的問題,須要同步
     * 刷新界面調用postInvalidate()能在非UI線程刷新
     * @author caizhiming
     */ 
    public synchronized void setProgress(int progress) {
        if(progress < 0){
            throw new IllegalArgumentException("progress must more than 0");
        }
        if(progress > max){
            this.progress = progress;
        }
        if(progress <= max){
            this.progress = progress;
            postInvalidate();
        }
    }

5、源碼下載

真題園網http://www.zhentiyuan.com

源碼下載:http://www.demodashi.com/demo/14680.html

相關文章
相關標籤/搜索