Android 2D Graphics學習(二)、Canvas篇2、Canvas裁剪和Region、RegionIterator

yangxi_001發表於2013-12-24

canvas 還提供裁剪的功能。 

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

1、首先介紹Region類

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

[java] view plaincopy
  1. /**構造方法*/  
  2.  public Region()  //建立一個空的區域  
  3.  public Region(Region region) //拷貝一個region的範圍  
  4.  public Region(Rect r)  //建立一個矩形的區域  
  5.  public Region(int left, int top, int right, int bottom) //建立一個矩形的區域  
  6.   
  7. /**一系列set方法,這些set方法,和上面構造方法形式差不多*/  
  8.  public void setEmpty() {  
  9.  public boolean set(Region region)   
  10.  public boolean set(Rect r)   
  11.  public boolean set(int left, int top, int right, int bottom)   
  12.  /*往一個Region中新增一個Path只有這種方法,引數clip代表這個整個Region的區域,在在裡面裁剪出path範圍的區域*/  
  13.  public boolean setPath(Path path, Region clip) //用指定的Path和裁剪範圍構建一個區域  
  14.   
  15. /**幾個判斷方法*/  
  16. public native boolean isEmpty();//判斷該區域是否為空  
  17. public native boolean isRect(); //是否是一個矩陣  
  18. public native boolean isComplex();//是否是多個矩陣組合  
  19.   
  20.   
  21. /**一系列的getBound方法,返回一個Region的邊界*/  
  22. public Rect getBounds()   
  23. public boolean getBounds(Rect r)   
  24. public Path getBoundaryPath()   
  25. public boolean getBoundaryPath(Path path)   
  26.   
  27.   
  28. /**一系列的判斷是否包含某點 和是否相交*/  
  29. public native boolean contains(int x, int y);//是否包含某點  
  30. public boolean quickContains(Rect r)   //是否包含某矩陣  
  31. public native boolean quickContains(int left, int top, int right,  
  32.                                         int bottom) //是否沒有包含某矩陣  
  33.  public boolean quickReject(Rect r) //是否沒和該矩陣相交  
  34.  public native boolean quickReject(int left, int top, int right, int bottom); //是否沒和該矩陣相交  
  35.  public native boolean quickReject(Region rgn);  //是否沒和該矩陣相交  
  36.   
  37. /**幾個平移變換的方法*/  
  38. public void translate(int dx, int dy)   
  39. public native void translate(int dx, int dy, Region dst);  
  40. public void scale(float scale) //hide  
  41. public native void scale(float scale, Region dst);//hide  
  42.   
  43.   
  44. /**一系列組合的方法*/  
  45. public final boolean union(Rect r)   
  46. public boolean op(Rect r, Op op) {  
  47. public boolean op(int left, int top, int right, int bottom, Op op)   
  48. public boolean op(Region region, Op op)   
  49. public boolean op(Rect rect, Region region, Op op)   

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

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

[java] view plaincopy
  1. 假設用region1  去組合region2   
  2. public enum Op {  
  3.         DIFFERENCE(0), //最終區域為region1 與 region2不同的區域  
  4.         INTERSECT(1), // 最終區域為region1 與 region2相交的區域  
  5.         UNION(2),      //最終區域為region1 與 region2組合一起的區域  
  6.         XOR(3),        //最終區域為region1 與 region2相交之外的區域  
  7.         REVERSE_DIFFERENCE(4), //最終區域為region2 與 region1不同的區域  
  8.         REPLACE(5); //最終區域為為region2的區域  
  9.  }  

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

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

2、什麼是裁剪

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

[java] view plaincopy
  1. @Override  
  2.         protected void onDraw(Canvas canvas) {  
  3.               Paint paint=new Paint();   
  4.               canvas.save();   
  5.               canvas.clipRect(new Rect(100,100,300,300));  
  6.               canvas.drawColor(Color.BLUE);//裁剪區域的rect變為藍色   
  7.               canvas.drawRect(new Rect(0,0,100,100), paint);//在裁剪的區域之外,不能顯示   
  8.               canvas.drawCircle(150,15050, paint);//在裁剪區域之內,能顯示  
  9.               canvas.restore();  
  10.         }  

裁剪並不像Matrix變換,它相對於mutable bitmap的座標是不會改變的。所以超出裁剪區域的繪製不會被顯示


3、裁剪的儲存和回滾

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


4、裁剪的方式

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

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

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

3、clipRegion。

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

[java] view plaincopy
  1.  Note that unlike  
  2. clipRect() and clipPath() which transform their arguments by the  
  3. current matrix, clipRegion() assumes its argument is already in the  
  4. coordinate system of the current layer's bitmap, and so not  
  5. transformation is performed.  
與clipRect和clipPath要使用當前的matrix進行變換不同。clipRegion不會進行轉換。也就是說canvas的matrix對clipRegion沒有影響。

[java] view plaincopy
  1. Paint paint=new Paint();  
  2.  canvas.scale(0.5f, 0.5f);  
  3.  canvas.save();  
  4.  canvas.clipRect(new Rect(100,100,200,200));//裁剪區域實際大小為50*50  
  5.  canvas.drawColor(Color.RED);  
  6.  canvas.restore();  
  7.    
  8.  canvas.drawRect(new Rect(0,0,100,100), paint);//矩形實際大小為50*50  
  9.    
  10.  canvas.clipRegion(new Region(new Rect(300,300,400,400)));//裁剪區域實際大小為100*100  
  11.  canvas.drawColor(Color.BLACK);  


可以看到,Canvas的變換 對clipRegion沒有作用。


ApiDemo中關於組合的例子:

[java] view plaincopy
  1. public class Clipping extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(new SampleView(this));  
  7.     }  
  8.   
  9.     private static class SampleView extends View {  
  10.         private Paint mPaint;  
  11.         private Path mPath;  
  12.   
  13.         public SampleView(Context context) {  
  14.             super(context);  
  15.             setFocusable(true);  
  16.   
  17.             mPaint = new Paint();  
  18.             mPaint.setAntiAlias(true);  
  19.             mPaint.setStrokeWidth(6);  
  20.             mPaint.setTextSize(16);  
  21.             mPaint.setTextAlign(Paint.Align.RIGHT);  
  22.   
  23.             mPath = new Path();  
  24.         }  
  25.   
  26.         private void drawScene(Canvas canvas) {  
  27.             canvas.clipRect(00100100);  
  28.   
  29.             canvas.drawColor(Color.WHITE);  
  30.   
  31.             mPaint.setColor(Color.RED);  
  32.             canvas.drawLine(00100100, mPaint);  
  33.   
  34.             mPaint.setColor(Color.GREEN);  
  35.             canvas.drawCircle(307030, mPaint);  
  36.   
  37.             mPaint.setColor(Color.BLUE);  
  38.             canvas.drawText("Clipping"10030, mPaint);  
  39.         }  
  40.   
  41.         @Override  
  42.         protected void onDraw(Canvas canvas) {  
  43.             canvas.drawColor(Color.GRAY);  
  44.   
  45.             canvas.save();  
  46.             canvas.translate(1010);  
  47.             drawScene(canvas);  
  48.             canvas.restore();  
  49.   
  50.             canvas.save();  
  51.             canvas.translate(16010);  
  52.             canvas.clipRect(10109090);  
  53.             canvas.clipRect(30307070, Region.Op.DIFFERENCE);  
  54.             drawScene(canvas);  
  55.             canvas.restore();  
  56.   
  57.             canvas.save();  
  58.             canvas.translate(10160);  
  59.             mPath.reset();  
  60.             canvas.clipPath(mPath); // makes the clip empty  
  61.             mPath.addCircle(505050, Path.Direction.CCW);  
  62.             canvas.clipPath(mPath, Region.Op.REPLACE);  
  63.             drawScene(canvas);  
  64.             canvas.restore();  
  65.   
  66.             canvas.save();  
  67.             canvas.translate(160160);  
  68.             canvas.clipRect(006060);  
  69.             canvas.clipRect(4040100100, Region.Op.UNION);  
  70.             drawScene(canvas);  
  71.             canvas.restore();  
  72.   
  73.             canvas.save();  
  74.             canvas.translate(10310);  
  75.             canvas.clipRect(006060);  
  76.             canvas.clipRect(4040100100, Region.Op.XOR);  
  77.             drawScene(canvas);  
  78.             canvas.restore();  
  79.   
  80.             canvas.save();  
  81.             canvas.translate(160310);  
  82.             canvas.clipRect(006060);  
  83.             canvas.clipRect(4040100100, Region.Op.REVERSE_DIFFERENCE);  
  84.             drawScene(canvas);  
  85.             canvas.restore();  
  86.         }  
  87.           
  88.     }  
  89. }  

效果圖:


5、裁剪的一個小用處

[java] view plaincopy
  1. public class ClippingRegion extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(new SampleView(this));  
  6.     }  
  7.   
  8.     private class SampleView extends View {  
  9.   
  10.         private Bitmap mBitmap;  
  11.         private int limitLength = 0;  
  12.         private int width;  
  13.         private int heigth;  
  14.         private static final int CLIP_HEIGHT = 30;  
  15.   
  16.         private boolean status = HIDE;//顯示還是隱藏的狀態,最開始為HIDE  
  17.         private static final boolean SHOW = true;//顯示圖片   
  18.         private static final boolean HIDE = false;//隱藏圖片  
  19.   
  20.         public SampleView(Context context) {  
  21.             super(context);  
  22.             mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image1);  
  23.             limitLength = width = mBitmap.getWidth();  
  24.             heigth = mBitmap.getHeight();  
  25.         }  
  26.   
  27.         @Override  
  28.         protected void onDraw(Canvas canvas) {  
  29.             Region region = new Region();  
  30.             int i = 0;  
  31.             while (i * CLIP_HEIGHT <= heigth) {//計算clip的區域  
  32.                 if (i % 2 == 0) {  
  33.                     region.union(new Rect(0, i * CLIP_HEIGHT, limitLength, (i + 1) * CLIP_HEIGHT));  
  34.                 } else {  
  35.                     region.union(new Rect(width - limitLength, i * CLIP_HEIGHT, width, (i + 1)  
  36.                             * CLIP_HEIGHT));  
  37.                 }  
  38.                 i++;  
  39.             }  
  40.   
  41.             canvas.clipRegion(region);  
  42.             canvas.drawBitmap(mBitmap, 00new Paint());  
  43.             if (status == HIDE) {//如果此時是隱藏  
  44.                 limitLength -= 5;  
  45.                 if(limitLength<=0)  
  46.                     status=SHOW;  
  47.             } else {//如果此時是顯示  
  48.                 limitLength += 5;  
  49.                 if(limitLength>=width)  
  50.                     status=HIDE;  
  51.             }  
  52.   
  53.             invalidate();  
  54.         }  
  55.     }  
  56. }  

效果就是一直這樣交叉的隱藏和顯示圖片

相關文章