Paint
画笔,在绘图这块,他就和我们使用的铅笔差不多,en...彩笔... 可变化粗细程度的彩笔。 大概就是这样。
抗锯齿
setAntiAlias(true)
防抖动
setDither(true)
双线性过滤
setFilterBitmap(true)//放大图导致马赛克问题优化
添加帽
setStrokeCap(Paint.Cap.BUTT)
Paint.Cap.ROUND (圆帽)
Paint.Cap.SQUARE(矩形帽)
Paint.Cap.BUTT(默认无帽)
填充模式
setStyle(Paint.Style.STROKE)
Paint.Style.STROKE(只描边)
Paint.Style.FILL (填充)
Paint.Style.FILL_AND_STROKE(填充 描边)
线条连接处样式
setStrokeJoin()
Paint.Join.BEVEL 平
Paint.Join.MITER 尖(默认)
Paint.Join.ROUND 圆
经初步测试 只有在setStyle(Paint.Style.STROKE) 或 FIll_AND_STROKE(即 有边时),才能生效。(画线时 需要使用path 而不是直接的drawableLine )
另外设置MITER属性,在角度非常小时,会自动改为BEVEL,防止无限长问题。setStrokeMiter(4)---28.96° 资料说明
setPathEffect()
设置所有拐角变成圆角 CornerPathEffect
Path path = new Path();
path.moveTo(200, 200);
path.lineTo(250, 300);
path.lineTo(300, 100);
path.lineTo(350, 250);
path.lineTo(400, 100);
path.lineTo(450, 600);
PathEffect pathEffect = new CornerPathEffect(20);
mPaint.setPathEffect(pathEffect);canvas.drawPath(path, mPaint);
设置间隔线 DashPathEffect
Path path =new Path();
path.moveTo(200,200);
path.lineTo(200,1200);
PathEffect pathEffect=new DashPathEffect(new float[]{20,40,10,10},0);(new float[]{“显示线段长度”,"隐藏线段长度"},偏移(相位差))------集合内必须成对出现
mPaint.setPathEffect(pathEffect);
canvas.drawPath(path,mPaint);
设置用特殊path 替代间隔线 PathDashPathEffect
Path path =new Path();
path.moveTo(200,200);
path.lineTo(200,400);
path.lineTo(400,400);
path.lineTo(400,200);
path.close();
//替代的path路径
Path path2=new Path();
path2.addArc(new RectF(0,0,20,20),0,180);
path2.close();
//替换的path,相邻图形的起始点距离,相位差,拐弯改变时的展示方式 TRANSLATE:位移 ROTATE:旋转 MORPH:变体
//经测试,目前都不好看 且拐角有拉长
PathEffect pathEffect=new PathDashPathEffect(path2,20,0,PathDashPathEffect.Style.MORPH);
mPaint.setPathEffect(pathEffect);
canvas.drawPath(path,mPaint);
还有很多方法:以下摘自https://blog.csdn.net/qq_27061049/article/details/102574020
设置线条随机偏移 DiscretePathEffect(float segmentLength, float deviation);
// segmentLength: 分段长度 deviation: 偏移距离
paint.setPathEffect(new DiscretePathEffect(50,10));
多种绘制:
SumPathEffect () 两种线条模式都执行 --分别绘制
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);
PathEffect discreteEffect = new DiscretePathEffect(20, 5);
PathEffect pathEffect = new SumPathEffect(dashEffect, discreteEffect);
paint.setPathEffect(pathEffect );
ComposePathEffect()线条组合模式 --一个执行完 再在这个基础上 继续执行
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);
PathEffect discreteEffect = new DiscretePathEffect(20, 5);
PathEffect pathEffect = new ComposePathEffect(dashEffect, discreteEffect);
paint.setPathEffect(pathEffect );
注意: PathEffect 在有些情况下不支持硬件加速,需要关闭硬件加速才能正常使用:
Canvas.drawLine() 和 Canvas.drawLines() 方法画直线时,setPathEffect()是不支持硬件加速的;
设置Gradient着色渐变 渲染
setShader()
1) LinearGradient 线性
起点x,y 终点x,y 渐变色(两种颜色有直接的方法 不需要用集合),位置,展示的模式
Shader.TileMode.REPEAT重复
Shader.TileMode.MIRROR镜像
Shader.TileMode.CLAMP只展示一次 CLAMP给我有种拉伸最后一帧的感觉
Shader shader=new LinearGradient(100,100,120,120,new int[]{Color.RED,Color.GREEN,Color.LTGRAY},new float[]{0,0.3f,1f},Shader.TileMode.REPEAT);
mPaint.setShader(shader);
canvas.drawLine(100,100,800,800,mPaint);
2) RadialGradient 径向渐变
学习累了,吃一串糖葫芦吧
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
Shader shader=new RadialGradient(400,400,100,new int[]{Color.RED,Color.GREEN,Color.LTGRAY},new float[]{0,0.3f,1f}, Shader.TileMode.REPEAT);
mPaint.setShader(shader);
mPaint.setStrokeJoin(Paint.Join.ROUND);
canvas.drawLine(100,100,800,800,mPaint);
canvas.drawCircle(250,250,100,mPaint);
canvas.drawCircle(400,400,100,mPaint);
canvas.drawCircle(550,550,100,mPaint);
3) SweepGradient 扫描渐变
Shader shader=new SweepGradient(400,400,new int[]{Color.WHITE,Color.LTGRAY,Color.GRAY},new float[]{0,0.5f,1f});
mPaint.setShader(shader);
canvas.drawCircle(400,400,100,mPaint);
4) BitmapShader 位图
提神洗脑,放上一张美女照片 ps:(身为已婚男士,当然是放自己媳妇啦)
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.p);
Shader shader=new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
canvas.drawCircle(400,400,100,mPaint);
TileMode的取值有三种:CLAMP 拉伸 REPEAT 重复 MIRROR 镜像
5)ComposeShader 混合渐变
ComposeShader shader=new ComposeShader(shader1,shader2, PorterDuff.Mode.ADD);
mPaint.setShader(shader);
canvas.drawCircle(400,400,100,mPaint);
mode可有这些选择 ...
滤镜效果
setColorFilter()
LightingColorFilter(int mul, int add) 设定 基本色素 黄绿黑,实现简单的光照效果
mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加:(去除某色改mul,增减色改add)
R' = R * mul.R / 0xff + add.R
G' = G * mul.G / 0xff + add.G
B' = B * mul.B / 0xff + add.B
所以: 0xffffff,0x000000,颜色不变
0x00ffff,0x000000,去红
0xffffff,0x660000,增强红色
PorterDuffColorFilter(int color,Mode mode)设定一种颜色 与mode规则运算
ColorFilter colorFilter=new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.ADD);
mPaint.setColorFilter(colorFilter);
ColorMatrix 颜色矩阵
我觉得使用矩阵更有逼格,所以硬着头皮,又大概了解了下大学的矩阵,高中的向量...
ColorMatrix colorMatrix=new ColorMatrix(new float[]{
5f,0f,0f,0f, -100f,
0f,5f,0f,0f, -254f,
0f,0f,5f,0f, -254f,
0f,0f,0f,1f,0f });
ColorFilter colorFilter=new ColorMatrixColorFilter(colorMatrix);
mPaint.setColorFilter(colorFilter);
canvas.drawBitmap(bitmap,0,200,mPaint);
以下是我的理解,假设bitmap里的图可以用这样来表示色度
图片转换模式
setXfermode
要想使用 setXfermode() 正常绘制,必须使用离屏缓存 (Off-screen Buffer) 把内容绘制在额外的层上,再把绘制好的内容贴回 View 中。
Bitmap bitmap1=BitmapFactory.decodeResource(getResources(),R.mipmap.ic_c);
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(),R.mipmap.hh);
//离层缓存 先存储分离前的图层
int saved=canvas.saveLayer(null,null);
canvas.drawBitmap(bitmap1,400,700,mPaint);
Xfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.XOR);
mPaint.setXfermode(xfermode);
canvas.drawBitmap(bitmap2,0,100,mPaint);
// 及时清除
mPaint.setXfermode(null);
canvas.restoreToCount(saved);
在我的测试中,其实并没有出现黑背景... 大概是我图太大了? 也不应该啊...
Bitmap bitmap1=BitmapFactory.decodeResource(getResources(),R.mipmap.hh);
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(),R.mipmap.finished);
//离层分离 先存储分离前的图层
int saved=canvas.saveLayer(null,null);
canvas.drawBitmap(bitmap1,200,500,mPaint);
Xfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
mPaint.setXfermode(xfermode);
canvas.drawBitmap(bitmap2,380,680,mPaint);
mPaint.setXfermode(null);
canvas.restoreToCount(saved);
阴影或者上层效果
绘制层下方的附加效果---阴影
setShadowLayer(float radius,float dx,float dy,int shadowColor) 模糊范围,横向/纵向 便宜 阴影颜色
在硬件加速开启的情况下, setShadowLayer() 只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。如果 shadowColor 是半透明的,阴影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor是不透明的,阴影的透明度就使用 paint 的透明度。
绘制层上附件效果(需关闭硬件加速)
setMaskFilter(MaskFilter maskfilter)
setColorFilter(filter) ,是对每个像素的颜色进行过滤;而这里的 setMaskFilter(filter) 则是基于整个画面来进行过滤
1)模糊效果的 BlurMaskFilter
NORMAL: 内外都模糊绘制
SOLID: 内部正常绘制,外部模糊
INNER: 内部模糊,外部不绘制
OUTER: 内部不绘制,外部模糊
new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER);
2)浮雕效果 EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius)
direction 是一个 3 个元素的数组,指定了光源的方向;
ambient 是环境光的强度,数值范围是 0 到 1;
specular 是炫光的系数; blurRadius 是应用光线的范围
MaskFilter maskFilter =new EmbossMaskFilter(new float[]{100,100,1},0.9f,10,1);
mPaint.setMaskFilter(maskFilter);
获取绘制的路径
线路径
getFillPath(src,dst); src是原路径 dst是目标路径
Path path =new Path();
path.moveTo(20,100);
path.lineTo(20,200);
path.lineTo(100,100);
canvas.drawPath(path,mPaint);
//目标路径 空
Path dstPath=new Path();
//将path 赋值给dstPath
mPaint.getFillPath(path,dstPath);
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(4);
canvas.drawPath(dstPath,mPaint);
获取文字绘制路径
getTextPath(text,0,length,x,y,dst);
canvas.translate(100,200);--->挪移画布 我之前的写法是 mTextPaint.getTextPath(text,0,text.length(),100,200,textPath); 效果一样
Path textPath=new Path();
mTextPaint.getTextPath(text,0,text.length(),0,50,textPath);
canvas.drawPath(textPath,mTextPaint);
设置paint文字居中
无论画笔多粗,绘制的线的正中间是指定的位置,故上下各有一半画笔粗度
文字在绘制时,默认绘制在指定位置的上方
1.测量文字高度
String text="800";
Rect textBound=new Rect();
mPaint.getTextBounds(text,0,text.length(),textBound); --->textBound 就是包括文字的外矩形
textBound.height()/2 ->获取一半的高度 要设定的高度+这个值 即可居中
2.测量文字宽度
mPaint.measureText(text)
(总宽度 -这个值)/2 即可设置为文字的开始位置
我还发现个小问题,设置Style为 fill属性时,即没有边属性,无论设置画笔多粗,文字都只会被TextSize影响。
关闭单个view的硬件加速
setLayerType(LAYER_TYPE_SOFTWARE,null);
2021-01-22 到 2021.1.27日 完成了paint的基本了解,感觉记录下来 收获许多,文中多次参考相关的网络资源,拜谢。