本節(jié)引言:
本節(jié)繼續(xù)帶來Android繪圖系列詳解之Canvas API詳解(Part 2)仁堪,今天要講解的是Canvas 中的ClipXxx方法族泽谨!我們可以看到文檔中給我們提供的Clip方法有三種類型: clipPath( )艾猜,clipRect( )姑裂,clipRegion( )糟秘;
通過Path,Rect旨巷,Region的不同組合巨缘,幾乎可以支持任意形狀的裁剪區(qū)域!
- Path:可以是開放或閉合的曲線采呐,線構(gòu)成的復(fù)雜的集合圖形
- Rect:矩形區(qū)域
- Region:可以理解為區(qū)域組合若锁,比如可以將兩個(gè)區(qū)域相加,相減斧吐,并又固,疑惑等!
1.Region.Op組合方式詳解
其實(shí)難點(diǎn)無非這個(gè)煤率,Region代表著區(qū)域仰冠,表示的是Canvas圖層上的某一塊封閉區(qū)域! 當(dāng)然蝶糯,有時(shí)間你可以自己慢慢去扣這個(gè)類洋只,而我們一般關(guān)注的只是他的一個(gè)枚舉值:Op
下面我們來看看個(gè)個(gè)枚舉值所起的作用: 我們假設(shè)兩個(gè)裁剪區(qū)域A和B,那么我們調(diào)用Region.Op對(duì)應(yīng)的枚舉值:
- DIFFERENCE:A和B的差集范圍,即A - B木张,只有在此范圍內(nèi)的繪制內(nèi)容才會(huì)被顯示;
- INTERSECT:即A和B的交集范圍端三,只有在此范圍內(nèi)的繪制內(nèi)容才會(huì)被顯示
- UNION:即A和B的并集范圍舷礼,即兩者所包括的范圍的繪制內(nèi)容都會(huì)被顯示;
- XOR:A和B的補(bǔ)集范圍郊闯,此例中即A除去B以外的范圍妻献,只有在此范圍內(nèi)的繪制內(nèi)容才會(huì)被顯示;
- REVERSE_DIFFERENCE:B和A的差集范圍团赁,即B - A育拨,只有在此范圍內(nèi)的繪制內(nèi)容才會(huì)被顯示;
- REPLACE:不論A和B的集合狀況欢摄,B的范圍將全部進(jìn)行顯示熬丧,如果和A有交集,則將覆蓋A的交集范圍怀挠;
如果你學(xué)過集合析蝴,那么畫個(gè)Venn(韋恩圖)就一清二楚了,沒學(xué)過绿淋?沒事闷畸,我們寫個(gè)例子來試試 對(duì)應(yīng)的結(jié)果~!寫個(gè)初始化畫筆以及畫矩形的方法:
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(6);
mPaint.setColor(getResources().getColor(R.color.blush));
}
private void drawScene(Canvas canvas){
canvas.drawRect(0, 0, 200, 200, mPaint);
}
Op.DIFFERENCE:
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二個(gè)
drawScene(canvas);
先后在(10,10)以及(50,50)為起點(diǎn)吞滞,裁剪了兩個(gè)100*100的矩形佑菩,得出的裁剪結(jié)果是:
A和B的差集 = A - (A和B相交的部分)
Op.INTERSECT:
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(50, 50, 150, 150, Region.Op.INTERSECT); //第二個(gè)
drawScene(canvas);
結(jié)果:
先后在(10,10)以及(50,50)為起點(diǎn),裁剪了兩個(gè)100*100的矩形裁赠,得出的裁剪結(jié)果是:
A和B的交集 = A和B相交的部分
Op.UNION:
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(40, 40, 140, 140, Region.Op.UNION); //第二個(gè)drawScene(canvas);
結(jié)果:
先后在(10,10)以及(50,50)為起點(diǎn)殿漠,裁剪了兩個(gè)100*100的矩形,得出的裁剪結(jié)果是: A和B的并集 = A的區(qū)域 + B的區(qū)域
Op.XOR:
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(50, 50, 150, 150, Region.Op.XOR); //第二個(gè)
drawScene(canvas);
結(jié)果:
先后在(10,10)以及(50,50)為起點(diǎn)佩捞,裁剪了兩個(gè)100*100的矩形凸舵,得出的裁剪結(jié)果是:
A和B的補(bǔ)集 = A和B的合集 - A和B的交集
Op.REVERSE_DIFFERENCE:
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(50, 50, 150, 150, Region.Op.REVERSE_DIFFERENCE); //第二個(gè)
drawScene(canvas);
**結(jié)果**:
![](http://upload-images.jianshu.io/upload_images/7508328-5e53fa51cec15f9d.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>先后在(10,10)以及(50,50)為起點(diǎn),裁剪了兩個(gè)100*100的矩形失尖,得出的裁剪結(jié)果是:
**B和A的差集 = B - A和B的交集**
# Op.REPLACE:
```java
canvas.clipRect(10, 10, 110, 110); //第一個(gè)
canvas.clipRect(50, 50, 150, 150, Region.Op.REPLACE); //第二個(gè)
drawScene(canvas);
結(jié)果:
先后在(10,10)以及(50,50)為起點(diǎn)啊奄,裁剪了兩個(gè)100*100的矩形,得出的裁剪結(jié)果是:
不論A和B的集合狀況掀潮,B的范圍將全部進(jìn)行顯示菇夸,如果和A有交集,則將覆蓋A的交集范圍仪吧;
2.clipRect方法詳解:
clipRect提供了七個(gè)重載方法:
參數(shù)介紹如下:
- rect:Rect對(duì)象庄新,用于定義裁剪區(qū)的范圍,Rect和RectF功能類似,精度和提供的方法不同而已
- left:矩形裁剪區(qū)的左邊位置
- top:矩形裁剪區(qū)的上邊位置
- right:矩形裁剪區(qū)的右邊位置
- bottom:矩形裁剪區(qū)的下邊位置
-
op:裁剪區(qū)域的組合方式
上述四個(gè)值可以是浮點(diǎn)型或者整型
使用案例
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(60);
canvas.translate(300,300);
canvas.clipRect(100, 100, 300, 300); //設(shè)置顯示范圍
canvas.drawColor(Color.WHITE); //白色背景
canvas.drawText("雙11择诈,繼續(xù)吃我的狗糧...", 150, 300, mPaint); //繪制字符串
運(yùn)行結(jié)果:
從上面的例子械蹋,不知道你發(fā)現(xiàn)了沒? clipRect會(huì)受Canvas變換的影響羞芍,白色區(qū)域是不花的區(qū)域哗戈,所以clipRect裁剪的是畫布, 而我們的繪制是在這個(gè)裁剪后的畫布上進(jìn)行的荷科!超過該區(qū)域的不顯示唯咬!
4.clipPath方法詳解:
相比起clipRect,clipPath就只有兩個(gè)重載方法畏浆,使用方法非常簡(jiǎn)單胆胰,自己繪制一個(gè)Paht然后 傳入即可!
使用示例:
這里復(fù)用我們以前在ImageView那里寫的圓形ImageView的例子~
實(shí)現(xiàn)代碼:
自定義ImageView:RoundImageView.java
public class RoundImageView extends ImageView {
private Bitmap mBitmap;
private Rect mRect = new Rect();
private PaintFlagsDrawFilter pdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG);
private Paint mPaint = new Paint();
private Path mPath=new Path();
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//傳入一個(gè)Bitmap對(duì)象
public void setBitmap(Bitmap bitmap) {
this.mBitmap = bitmap;
}
private void init() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mPaint.setAntiAlias(true);// 抗鋸尺
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mBitmap == null)
{
return;
}
mRect.set(0,0,getWidth(),getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
mPath.addCircle(getWidth() / 2, getWidth() / 2, getHeight() / 2, Path.Direction.CCW);
canvas.clipPath(mPath, Region.Op.REPLACE);
canvas.drawBitmap(mBitmap, null, mRect, mPaint);
canvas.restore();
}
}
運(yùn)行效果圖:
另外使用該方法制作的圓角ImageView會(huì)有鋸齒明顯刻获,即使你為Paint蜀涨,Canvas設(shè)置了 抗鋸齒也沒用~假如你要求高的,可以使用Xfermode-PorterDuff設(shè)置圖像混排來實(shí)現(xiàn)蝎毡, 基本沒鋸齒