Canvas&Paint[]Paint

【参考链接】

Xfermodehttps://segmentfault.com/a/1190000006753544

androidcanvas layer (图层)详解与进阶http://blog.****.net/cquwentao/article/details/51423371

 

画布用于控制形状。而画笔用于控制样式。

 

setStyle

设置是FillStroke还是FillAndStroke

stroke是平分分布的,比如说stroke=8,则4个像素在边界外,4个像素在边界上和边界内,所以stroke值最好为偶数。

注:Stroke模式对drawPointdrawLine无效,未设置strokeWidth则宽度为1,否则为strokeWidth;对drawBitmap无效。

Canvas&Paint[]Paint


Canvas&Paint[]Paint

Canvas&Paint[]Paint

 

setColor

设置画笔颜色

注:对drawBitmap无效

 

setShader

可以通过setShader()来给画笔设置渐变Gradient或者渲染Shader

设置的时候还需要设置重复方式。

会覆盖setColor()效果

注:对drawBitmap无效

 

1.     Gradient

//这个坐标并不是当对于绘图元素的坐标//还是当前画布坐标系的坐标
LinearGradientgradient=newLinearGradient(0,0,600,600,Color.BLUE,Color.YELLOW,Shader.TileMode.REPEAT);
paintAll.setShader(gradient);
canvas.drawRect(0,0,800,800,paintAll);

 

Canvas&Paint[]Paint

Canvas&Paint[]Paint

 

相当于是用一条垂直于指定线段的无线长度色带进行了填充

 

2.     Shader

BitmapbitmapShader=BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);

BitmapShader shader=newBitmapShader(bitmapShader,
       
Shader.TileMode.REPEAT,
       
Shader.TileMode.REPEAT);
paintAll.setShader(shader);

Canvas&Paint[]Paint

Canvas&Paint[]Paint

依然是以整个画布为区域进行渲染的

 

 

setColorFilter

绘图的时候叠加颜色矩阵处理

ColorMatrix类来表示一个4x5的颜色矩阵,可以用色调、亮度、饱和度生成,也可以直接用数值。

如下是对上面的Gradient叠加一个反色矩阵时的效果,可以看到将渐变颜色改变了

 

Canvas&Paint[]Paint

Canvas&Paint[]Paint

 

setXfermode

在绘制新元素的时候,将 当前图层的 和新元素区域相同的 元素,和新元素进行叠加。

比如说新元素位于已有元素下方、新元素和已有元素进行异或等。

相当于是两个相同大小的切片按照不同的效果进行叠加。

 

把已有元素叫做dst,新元素叫做src

比如说有如下两个图片

dst蓝色方形,8像素内边框,src红色圆形,4像素内边框,大小都是200x200

Canvas&Paint[]PaintCanvas&Paint[]Paint

在同一区域绘制时,叠加效果如下

Canvas&Paint[]Paint

举几个说明一下

SRC_OVER,将SRC叠加到DST上面

DST_OVER,将DST叠加到SRC上面

SRC_IN,只显示合集中的SRC部分

DST_IN,只显示合集中的DST部分

SRC_OUT,显示SRC,去除合集部分

DST_OUT,显示DST,去除合集部分

 

protected voidonCreate(Bundle savedInstanceState) {
   
super.onCreate(savedInstanceState);
   
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
   
setContentView(R.layout.activity_main);

   
Bitmap bmp=Bitmap.createBitmap(2000,2000,Bitmap.Config.ARGB_8888);
   
Canvas canvas=newCanvas(bmp);

   
//默认画笔
   
Paint paintAll=newPaint();
   
paintAll.setAlpha(255);//不透明度//完全不透明
   
paintAll.setAntiAlias(true);
   
paintAll.setTextSize(20);

   
//在新的图层上进行叠加操作
   
intsave = canvas.saveLayer(0,0,2000,2000,null,Canvas.ALL_SAVE_FLAG);

    int
i=0;
    int
x =50;
    int
y =50;

    for
(PorterDuff.Mode mode : PorterDuff.Mode.values()){

       
if(i==1|| (i-1)%4==0){//换行
           
x =20;//x轴右移200
           
y +=320;
       
}

       
//先画正方形后画圆//图片大小都是200
       
paintAll.setXfermode(null);
       
canvas.drawText(mode.name(),x + 100,y,paintAll);
       
canvas.drawBitmap(drawDstRect(),x,y,paintAll);

       
paintAll.setXfermode(newPorterDuffXfermode(mode));
        
canvas.drawBitmap(drawSrcCircle(),x,y,paintAll);

       
x +=280;
       
i++;
   
}

    paintAll.setXfermode(
null);
   
canvas.restoreToCount(save);//恢复到上次状态,并且将新添加的图层绘制到画布上

   
ImageView iv = (ImageView)findViewById(R.id.iv);
   
iv.setImageBitmap(bmp);
}

privateBitmapdrawDstRect(){//蓝色正方形

   
Bitmap bm = Bitmap.createBitmap(200,200,Bitmap.Config.ARGB_8888);//图片大小为200
   
Canvas cavas =newCanvas(bm);

   
Paint paint =newPaint(Paint.ANTI_ALIAS_FLAG);
   
paint.setAntiAlias(true);
   
paint.setColor(Color.parseColor("#3F51B5"));

   
paint.setStyle(Paint.Style.STROKE);
   
paint.setStrokeWidth(16);
   
cavas.drawRect(newRect(0,0,200,200),paint);//图片大小只有200,所以这里只有8个像素的内框

   
paint.setStyle(Paint.Style.FILL);
   
cavas.drawRect(newRectF(0,0,70,70),paint);//长宽70的一个正方形

   
returnbm;
}

private BitmapdrawSrcCircle(){//红色圆形
   
Bitmap bm = Bitmap.createBitmap(200,200,Bitmap.Config.ARGB_8888);//图片大小也为200
   
Canvas cavas =newCanvas(bm);

   
Paint paint =newPaint(Paint.ANTI_ALIAS_FLAG);
   
paint.setAntiAlias(true);
   
paint.setColor(Color.parseColor("#FF4081"));

   
paint.setStyle(Paint.Style.STROKE);
   
paint.setStrokeWidth(8);
   
cavas.drawRect(newRect(0,0,200,200),paint);

   
paint.setStyle(Paint.Style.FILL);
   
cavas.drawCircle(70,70,35,paint);//半径35的一个圆//距离上下各35
   
returnbm;
}

 

需要注意的是,Xfermode是跟同图层中的所有已有元素进行叠加,所以一般情况下是在新建图层上进行叠加。

如下代码,开不开启图层的效果是不同的。

Canvas canvas=newCanvas(bmp);
canvas.drawColor(Color.parseColor("#000000"));

//默认画笔
Paint paintAll=newPaint();
paintAll.setAlpha(255);//不透明度//完全不透明
paintAll.setAntiAlias(true);

//在新的图层上进行叠加操作
intsave = canvas.saveLayer(0,0,2000,2000,null,Canvas.ALL_SAVE_FLAG);

//先画正方形后画圆//图片大小都是200
canvas.drawBitmap(drawDstRect(),0,0,paintAll);

paintAll.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.XOR));
canvas.drawBitmap(drawSrcCircle(),0,0,paintAll);

paintAll.setXfermode(null);
canvas.restoreToCount(save);//恢复到上次状态,并且将新添加的图层绘制到画布上

 

Canvas&Paint[]Paint  Canvas&Paint[]Paint

不过我也实验了一下,设置Viewbackground并不影响其onDraw()中的Canvas的初始图层。说明传递给onDraw()Canvas已经叠加了图层了,其实这也可以通过在onDraw()的第一行打印canvas.getSaveCount()验证。