Paint基础用法

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可有这些选择 ... 

DST表示下层圆  SRC表示上层方 原始为 下圆上方

滤镜效果


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里的图可以用这样来表示色度 

大概的算法就是这样,Android源码中是这样讲的:
上面差不多就不说了,下面是个比较好的思路,实现颜色反转,可以尝试使用,使RGB都为负数,再通过+255,使之在正常范围

图片转换模式

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的基本了解,感觉记录下来 收获许多,文中多次参考相关的网络资源,拜谢。

你可能感兴趣的:(Paint基础用法)