天天看點

canvas解析

Android Canvas裁剪和Region、RegionIterator

轉自:http://blog.csdn.net/lonelyroamer/article/details/8349601

canvas 還提供裁剪的功能。

裁剪功能由Canvas提供的一系列的clip…方法 和quickReject方法來完成。 前面已經提到,真正提供可繪制區域的是Canvas内部的mutable bitmap。 Canvas更像是一個圖層,我們隻能在這上面的圖層來繪制東西。

1、首先介紹Region類

Region,中文意思即區域的意思,它表示的是canvas圖層上的某一塊封閉的區域。

/**構造方法*/
 public Region()  //建立一個空的區域
 public Region(Region region) //拷貝一個region的範圍
 public Region(Rect r)  //建立一個矩形的區域
 public Region(int left, int top, int right, int bottom) //建立一個矩形的區域

/**一系列set方法,這些set方法,和上面構造方法形式差不多*/
 public void setEmpty() {
 public boolean set(Region region) 
 public boolean set(Rect r) 
 public boolean set(int left, int top, int right, int bottom) 
 /*往一個Region中添加一個Path隻有這種方法,參數clip代表這個整個Region的區域,在在裡面裁剪出path範圍的區域*/
 public boolean setPath(Path path, Region clip) //用指定的Path和裁剪範圍建構一個區域

/**幾個判斷方法*/
public native boolean isEmpty();//判斷該區域是否為空
public native boolean isRect(); //是否是一個矩陣
public native boolean isComplex();//是否是多個矩陣組合


/**一系列的getBound方法,傳回一個Region的邊界*/
public Rect getBounds() 
public boolean getBounds(Rect r) 
public Path getBoundaryPath() 
public boolean getBoundaryPath(Path path) 


/**一系列的判斷是否包含某點 和是否相交*/
public native boolean contains(int x, int y);//是否包含某點
public boolean quickContains(Rect r)   //是否包含某矩陣
public native boolean quickContains(int left, int top, int right,
                                        int bottom) //是否沒有包含某矩陣
 public boolean quickReject(Rect r) //是否沒和該矩陣相交
 public native boolean quickReject(int left, int top, int right, int bottom); //是否沒和該矩陣相交
 public native boolean quickReject(Region rgn);  //是否沒和該矩陣相交

/**幾個平移變換的方法*/
public void translate(int dx, int dy) 
public native void translate(int dx, int dy, Region dst);
public void scale(float scale) //hide
public native void scale(float scale, Region dst);//hide


/**一系列組合的方法*/
public final boolean union(Rect r) 
public boolean op(Rect r, Op op) {
public boolean op(int left, int top, int right, int bottom, Op op) 
public boolean op(Region region, Op op) 
public boolean op(Rect rect, Region region, Op op)
           

上面幾乎是Region的所有API,很好了解,主要說明一下最後的一組關于Region組合的方式。組合即目前的Region和另外的一個Region組合,可以用不同的Op方式來進行組合。

Op是一個枚舉,定義在Region類中。

假設用region1  去組合region2   
public enum Op {  
        DIFFERENCE(), //最終區域為region1 與 region2不同的區域  
        INTERSECT(), // 最終區域為region1 與 region2相交的區域  
        UNION(),      //最終區域為region1 與 region2組合一起的區域  
        XOR(),        //最終區域為region1 與 region2相交之外的區域  
        REVERSE_DIFFERENCE(), //最終區域為region2 與 region1不同的區域  
        REPLACE(); //最終區域為為region2的區域  
 }  

           

ApiDemo中已經提供了一個關于組合的例子,在最後面給出。

Android還提供了一個RegionIterator來對Region中的所有矩陣進行疊代,可以使用該類,獲得某個Region的所有矩陣。比較簡單。

2、什麼是裁剪

裁剪Clip,即裁剪Canvas圖層,我們繪制的東西,隻能在裁剪區域的範圍能才能顯示出來。

@Override  
        protected void onDraw(Canvas canvas) {  
              Paint paint=new Paint();   
              canvas.save();   
              canvas.clipRect(new Rect(,,,));  
              canvas.drawColor(Color.BLUE);//裁剪區域的rect變為藍色   
              canvas.drawRect(new Rect(,,,), paint);//在裁剪的區域之外,不能顯示   
              canvas.drawCircle(,, , paint);//在裁剪區域之内,能顯示  
              canvas.restore();  
        }  
           

裁剪并不像Matrix變換,它相對于mutable bitmap的坐标是不會改變的。是以超出裁剪區域的繪制不會被顯示

3、裁剪的儲存和復原

在之前已經提到了,canvas.save()和canvas.restore()不僅對matrix有效,同樣對clip有類似的效果。

4、裁剪的方式

Canvas提供了三種裁剪的方式:

1、最基本的clipRect,裁剪一個矩形

2、clipPath,裁剪Path包括的範圍,Path所包括的範圍不是空的才有效。

3、clipRegion。

Region在前面已經介紹過了,其實Region就是一個對區域組合的一個封裝。但是它和clipRect和clipPath的最大差別在于下面:

與clipRect和clipPath要使用目前的matrix進行變換不同。clipRegion不會進行轉換。也就是說canvas的matrix對clipRegion沒有影響。

Paint paint=new Paint();  
 canvas.scale(f, f);  
 canvas.save();  
 canvas.clipRect(new Rect(,,,));//裁剪區域實際大小為50*50  
 canvas.drawColor(Color.RED);  
 canvas.restore();  

 canvas.drawRect(new Rect(,,,), paint);//矩形實際大小為50*50  

 canvas.clipRegion(new Region(new Rect(,,,)));//裁剪區域實際大小為100*100  
 canvas.drawColor(Color.BLACK);  
           

ApiDemo中關于組合的例子

public class Clipping extends Activity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(new SampleView(this));  
    }  

    private static class SampleView extends View {  
        private Paint mPaint;  
        private Path mPath;  

        public SampleView(Context context) {  
            super(context);  
            setFocusable(true);  

            mPaint = new Paint();  
            mPaint.setAntiAlias(true);  
            mPaint.setStrokeWidth();  
            mPaint.setTextSize();  
            mPaint.setTextAlign(Paint.Align.RIGHT);  

            mPath = new Path();  
        }  

        private void drawScene(Canvas canvas) {  
            canvas.clipRect(, , , );  

            canvas.drawColor(Color.WHITE);  

            mPaint.setColor(Color.RED);  
            canvas.drawLine(, , , , mPaint);  

            mPaint.setColor(Color.GREEN);  
            canvas.drawCircle(, , , mPaint);  

            mPaint.setColor(Color.BLUE);  
            canvas.drawText("Clipping", , , mPaint);  
        }  

        @Override  
        protected void onDraw(Canvas canvas) {  
            canvas.drawColor(Color.GRAY);  

            canvas.save();  
            canvas.translate(, );  
            drawScene(canvas);  
            canvas.restore();  

            canvas.save();  
            canvas.translate(, );  
            canvas.clipRect(, , , );  
            canvas.clipRect(, , , , Region.Op.DIFFERENCE);  
            drawScene(canvas);  
            canvas.restore();  

            canvas.save();  
            canvas.translate(, );  
            mPath.reset();  
            canvas.clipPath(mPath); // makes the clip empty  
            mPath.addCircle(, , , Path.Direction.CCW);  
            canvas.clipPath(mPath, Region.Op.REPLACE);  
            drawScene(canvas);  
            canvas.restore();  

            canvas.save();  
            canvas.translate(, );  
            canvas.clipRect(, , , );  
            canvas.clipRect(, , , , Region.Op.UNION);  
            drawScene(canvas);  
            canvas.restore();  

            canvas.save();  
            canvas.translate(, );  
            canvas.clipRect(, , , );  
            canvas.clipRect(, , , , Region.Op.XOR);  
            drawScene(canvas);  
            canvas.restore();  

            canvas.save();  
            canvas.translate(, );  
            canvas.clipRect(, , , );  
            canvas.clipRect(, , , , Region.Op.REVERSE_DIFFERENCE);  
            drawScene(canvas);  
            canvas.restore();  
        }  

    }  
}  
           

5、裁剪的一個小用處

public class ClippingRegion extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(new SampleView(this));  
    }  

    private class SampleView extends View {  

        private Bitmap mBitmap;  
        private int limitLength = ;  
        private int width;  
        private int heigth;  
        private static final int CLIP_HEIGHT = ;  

        private boolean status = HIDE;//顯示還是隐藏的狀态,最開始為HIDE  
        private static final boolean SHOW = true;//顯示圖檔   
        private static final boolean HIDE = false;//隐藏圖檔  

        public SampleView(Context context) {  
            super(context);  
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image1);  
            limitLength = width = mBitmap.getWidth();  
            heigth = mBitmap.getHeight();  
        }  

        @Override  
        protected void onDraw(Canvas canvas) {  
            Region region = new Region();  
            int i = ;  
            while (i * CLIP_HEIGHT <= heigth) {//計算clip的區域  
                if (i %  == ) {  
                    region.union(new Rect(, i * CLIP_HEIGHT, limitLength, (i + ) * CLIP_HEIGHT));  
                } else {  
                    region.union(new Rect(width - limitLength, i * CLIP_HEIGHT, width, (i + )  
                            * CLIP_HEIGHT));  
                }  
                i++;  
            }  

            canvas.clipRegion(region);  
            canvas.drawBitmap(mBitmap, , , new Paint());  
            if (status == HIDE) {//如果此時是隐藏  
                limitLength -= ;  
                if(limitLength<=)  
                    status=SHOW;  
            } else {//如果此時是顯示  
                limitLength += ;  
                if(limitLength>=width)  
                    status=HIDE;  
            }  

            invalidate();  
        }  
    }  
}
           

轉自:http://blog.csdn.net/lonelyroamer/article/details/8349601