Canvas&Paint[]Paint
【参考链接】
Xfermode篇https://segmentfault.com/a/1190000006753544
androidcanvas layer (图层)详解与进阶http://blog.****.net/cquwentao/article/details/51423371
画布用于控制形状。而画笔用于控制样式。
setStyle
设置是Fill、Stroke还是FillAndStroke
stroke是平分分布的,比如说stroke=8,则4个像素在边界外,4个像素在边界上和边界内,所以stroke值最好为偶数。
注:Stroke模式对drawPoint、drawLine无效,未设置strokeWidth则宽度为1,否则为strokeWidth;对drawBitmap无效。
|
|
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);
|
|
相当于是用一条垂直于指定线段的无线长度色带进行了填充
2. Shader
BitmapbitmapShader=BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
BitmapShader shader=newBitmapShader(bitmapShader,
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
paintAll.setShader(shader);
|
|
依然是以整个画布为区域进行渲染的
setColorFilter
绘图的时候叠加颜色矩阵处理
用ColorMatrix类来表示一个4x5的颜色矩阵,可以用色调、亮度、饱和度生成,也可以直接用数值。
如下是对上面的Gradient叠加一个反色矩阵时的效果,可以看到将渐变颜色改变了
|
|
setXfermode
在绘制新元素的时候,将 当前图层的 和新元素区域相同的 元素,和新元素进行叠加。
比如说新元素位于已有元素下方、新元素和已有元素进行异或等。
相当于是两个相同大小的切片按照不同的效果进行叠加。
把已有元素叫做dst,新元素叫做src
比如说有如下两个图片
dst蓝色方形,8像素内边框,src红色圆形,4像素内边框,大小都是200x200
在同一区域绘制时,叠加效果如下
举几个说明一下
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);//恢复到上次状态,并且将新添加的图层绘制到画布上
不过我也实验了一下,设置View的background并不影响其onDraw()中的Canvas的初始图层。说明传递给onDraw()的Canvas已经叠加了图层了,其实这也可以通过在onDraw()的第一行打印canvas.getSaveCount()验证。