自定义View一:绘制-Paint

1、Paint类

自定义控件具有很强的灵活性,可以根据你的想法画出各种各样的图案,在Android中如果是自定义控件的话,Paint这个类用的还是较多的,先来看一下这个类的注释:

/**
 * The Paint class holds the style and color information about how to draw
 * geometries, text and bitmaps.
 */

使用保存的样式和颜色信息,绘制几何图形,文本和bitmap。

2、Paint方法

mPaint.setColor(Color.RED);// 设置颜色
mPaint.setARGB(255, 255, 255, 0); // 设置 Paint对象颜色,范围为0~255
mPaint.setAlpha(200); // 设置alpha不透明度,范围为0~255
mPaint.setAntiAlias(true); // 抗锯齿
mPaint.setStyle(Paint.Style.FILL); //描边效果
mPaint.setStrokeWidth(4);//描边宽度
mPaint.setStrokeCap(Paint.Cap.ROUND); //圆角效果
mPaint.setStrokeJoin(Paint.Join.MITER);//拐角风格
mPaint.setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)); //设置环形渲染器
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); //设置图层混合模式
mPaint.setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)); //设置颜色过滤器

3、线条形状

3.1 Paint. setAntiAlias

设置抗锯齿

3.2 Paint.Style

paint.setStyle(Paint.Style.FILL); //填充所有
paint.setStyle(Paint.Style.STROKE); //描边效果,只画出线条
paint.setStyle(Paint.Style.FILL_AND_STROKE); //填充内部和描边

3.3 Paint.cap

paint.setStrokeCap(Paint.Cap.BUTT); //默认效果,如绘制的正方形,就是正方行
paint.setStrokeCap(Paint.Cap.ROUND); //绘制的图形两边会有圆角效果,两边的圆角是在SQUARE 的基础上延申出一部分形成圆角
paint.setStrokeCap(Paint.Cap.SQUARE); //BUTT 的基础上,两边延申出去一部分

3.4 Paint.Join

paint.setStrokeJoin(Paint.Join.MITER);//拐角风格,直角
paint.setStrokeJoin(Paint.Join.BEVEL);//拐角风格,切割
paint.setStrokeJoin(Paint.Join.ROUND);//拐角风格,圆角

3.5 Paint. StrokeMiter

paint.setStrokeMiter(1.7f);

对于 setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值。

4、drawBitmap

4.1 Paint.setXfermode

4.2 Paint.setDither

设置图像的抖动

paint.setDither(true);

4.3 Paint.setFilterBitmap

是否使用双线性过滤来绘制 Bitmap

图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑。

paint.setFilterBitmap(true);

5、drawText

5.1 Paint.Align

paint.setTextAlign(Paint.Align.LEFT);  //左对齐,默认
paint.setTextAlign(Paint.Align.CENTER);//居中对齐
paint.setTextAlign(Paint.Align.RIGHT); //右对齐

5.2 Paint.FontMetrics

字体的度量,是指对于指定字号的某种字体,在度量方面的各种属性,其描述参数包括:

Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float top = fontMetrics.top;
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
float bottom = fontMetrics.bottom;
float leading = fontMetrics.leading;

baseline:字符基线

ascent:字符最高点到baseline的推荐距离

top:字符最高点到baseline的最大距离

descent:字符最低点到baseline的推荐距离

bottom:字符最低点到baseline的最大距离

leading:行间距,即前一行的descent与下一行的ascent之间的距离

     参考:https://blog.csdn.net/flyeek/article/details/43934945

5.3 Paint.Measure

float[] measuredWidth = new float[16];
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
//字符的高度
float textHeight = fontMetrics.descent + Math.abs(fontMetrics.ascent);
//字符串的长度;
float textLength = mPaint.measureText(text);
//measuredWidth每一个字符的长度;textWidths字符数
int textWidths = mPaint.getTextWidths(text, measuredWidth);
//截取的最大距离中字符个数
int breakText = mPaint.breakText(text, true, 50, null);

breakText()这个方法:

/**
 * 计算出要截取的字符个数
 *
 * @param text            测量的字符串
 * @param start           测量开始的位置
 * @param end             测量结束的位置
 * @param measureForwards 测量方向,true从前往后,false从后往前
 * @param maxWidth        截取的字符串最大宽度
 * @param measuredWidth   截取字符串实际宽度
 * @return 需要截取的字符个数
 */
public int breakText(CharSequence text, int start, int end, 
                     boolean measureForwards, float maxWidth,
                     float[] measuredWidth);

5.4 Paint.setShadowLayer

mPaint.setShadowLayer(10, 10, 10, Color.RED);
canvas.drawText("ANDROID", 0, 100, mPaint);

注意:

在硬件加速开启的情况下, setShadowLayer() 只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。

如果 shadowColor 是半透明的,阴影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的,阴影的透明度就使用 paint 的透明度。

6、PathEffect

使用 PathEffect 来给图形的轮廓设置效果。

Android 中的 6 种 PathEffect:

单一效果: CornerPathEffect、DiscretePathEffect、DashPathEffect、PathDashPathEffect

组合效果:SumPathEffect ComposePathEffect

6.1 CornerPathEffect

把所有拐角变成圆角

PathEffect effect = new CornerPathEffect(60);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.2 DiscretePathEffect

把线条进行随机的偏离,让轮廓变得乱七八糟。

DiscretePathEffect 具体的做法是,把绘制改为使用定长的线段来拼接,并且在拼接的时候对路径进行随机偏离。DiscretePathEffect(float segmentLength, float deviation) 的两个参数中, segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。这两个值设置得不一样,显示效果也会不一样。

PathEffect effect = new DiscretePathEffect(20, 10);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.3 DashPathEffect

使用虚线来绘制线条。

它的构造方法 DashPathEffect(float[] intervals, float phase) 中, 第一个参数 intervals 是一个数组,它指定了虚线的格式:数组中元素必须为偶数(最少是 2 个),按照「画线长度、空白长度、画线长度、空白长度」……的顺序排列,例如上面代码中的 20, 5, 10, 5 就表示虚线是按照「画 20 像素、空 5 像素、画 10 像素、空 5 像素」的模式来绘制;第二个参数 phase 是虚线的偏移量。

PathEffect effect = new DashPathEffect(new float[]{30,15,60, 15}, 10);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.4 PathDashPathEffect

这个方法比 DashPathEffect 多一个前缀 Path ,所以顾名思义,它是使用一个Path 来绘制「虚线」。

它的构造方法:PathDashPathEffect(Path shape, float advance, float phase, Style style );

PathDashPathE中, shape 参数是用来绘制的 Path ; advance 是两个相邻的 shape 段之间的间隔,不过注意,这个间隔是两个 shape 段的起点的间隔,而不是前一个的终点和后一个的起点的距离; phase 和 DashPathEffect 中一样,是虚线的偏移;最后一个参数 style,是用来指定拐弯改变的时候 shape 的转换方式。style 的类型为 PathDashPathEffect.Style ,是一个 enum ,具体有三个值:

TRANSLATE:位移

ROTATE:旋转

MORPH:变体

Path shape = new Path();
shape.moveTo(0,20);
shape.lineTo(20,0);
shape.lineTo(40, 20);

PathEffect effect = new PathDashPathEffect(shape,50,40, PathDashPathEffect.Style.TRANSLATE);
mPaint.setPathEffect(effect);
canvas.drawRoundRect(0,0, 400,300, 72,72, mPaint);

6.5 SumPathEffect

这是一个组合效果类的 PathEffect 。它的行为特别简单,就是分别按照两种PathEffect 分别对目标进行绘制。

PathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 10);
PathEffect discretePathEffect = new DiscretePathEffect(40, 20);
PathEffect sumPathEffect = new SumPathEffect(dashPathEffect, discretePathEffect);
mPaint.setPathEffect(sumPathEffect);
canvas.drawPath(mPath, mPaint);

6.6 ComposePathEffect

这也是一个组合效果类的 PathEffect 。不过它是先对目标 Path 使用一个PathEffect,然后再对这个改变后的 Path 使用另一个 PathEffect。

PathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 10);
PathEffect discretePathEffect = new DiscretePathEffect(40, 20);
PathEffect sumPathEffect = new ComposePathEffect(dashPathEffect, discretePathEffect);
mPaint.setPathEffect(sumPathEffect);
canvas.drawPath(mPath, mPaint);

它的构造方法ComposePathEffect(PathEffect outerpe, PathEffect innerpe) 中的两个PathEffect 参数, innerpe 是先应用的, outerpe 是后应用的。所以上面的代码就是「先偏离,再变虚线」。而如果把两个参数调换,就成了「先变虚线,再偏离」。

7、MaskFilter

为之后的绘制设置 MaskFilter。上一个方法 setShadowLayer() 是设置的在绘制层下方的附加效果;而这个 MaskFilter 和它相反,设置的是在绘制层上方的附加效果。

MaskFilter 有两种: BlurMaskFilter 和 EmbossMaskFilter。

7.1 BlurMaskFilter

模糊效果

MaskFilter filter = new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER);
mPaint.setMaskFilter(filter);
canvas.drawBitmap(bitmap, 100, 100, mPaint);

它的构造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style)中, radius 参数是模糊的范围, style 是模糊的类型。一共有四种:

NORMAL : 内外都模糊绘制

SOLID : 内部正常绘制,外部模糊

INNER : 内部模糊,外部不绘制

OUTER : 内部不绘制,外部模糊

7.2 EmbossMaskFilter

浮雕效果

EmbossMaskFilter (float[] direction,    // 3个浮点值的数组,X、Y、Z方向指定光源
                  float ambient,        // 环境光亮度,取值范围是0~1
                  float specular,       // 反射等级,值如:8
                  float blurRadius)     // 照明前的模糊量,值如:3
MaskFilter filter = new EmbossMaskFilter(new float[]{-1, 1, -1}, 1f, 8, 3.5f);
mPaint.setMaskFilter(filter);
canvas.drawText("ANDROID", 0, 200, mPaint);

效果不是很明显…

8.Shader

Shader 这个英文单词很多人没有见过,它的中文叫做「着色器」,也是用于设置绘制颜色的。在 Android 的绘制里使用 Shader ,并不直接用 Shader 这个类,而是用它的几个子类:

LinearGradient、RadialGradient、SweepGradient、BitmapShader、 ComposeShader

8.1 LinearGradient线性渲染

**
 * 1.线性渲染,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile)
 * (x0,y0):渐变起始点座标
 * (x1,y1):渐变结束点座标
 * colors:渐变数组
 * positions:位置数组,position的取值范围[0,1],作用是指定某个位置的颜色值,如果传null,渐变就线性变化。
 * tile:用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法,分为三种:CLAMP(最后1像素拉伸) REPEAT(重复) MIRROR(镜影)
 */
//渲染一个x和y的座标点是(200, 100),颜色是从绿色到红色渐变,在0.6f(60%)的时候开始渐变成红色,1 最后是蓝色 ,绘制区域大于渲染器指定区域的填充是1像素拉伸
Shader lineShader = new LinearGradient(0, 0, 200, 0,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        new float[]{0, 0.6f, 1},
        Shader.TileMode.REPEAT);

8.2 RadialGradient环形渲染

/**
 * 环形渲染,RadialGradient(float centerX, float centerY, float radius, @ColorInt int colors[], @Nullable float stops[], TileMode tileMode)
 * centerX ,centerY:shader的中心座标,开始渐变的座标
 * radius:渐变的半径
 * centerColor,edgeColor:中心点渐变颜色,边界的渐变颜色
 * colors:渐变颜色数组
 * stoops:渐变位置数组,类似扫描渐变的positions数组,取值[0,1],中心点为0,半径到达位置为1.0f
 * tileMode:shader未覆盖以外的填充模式。
 */
Shader shader = new RadialGradient(200, 200, 130,
        new int[]{Color.GREEN, Color.YELLOW, Color.RED},
        null, Shader.TileMode.REPEAT);
mPaint.setShader(shader);

8.3 SweepGradient扫描渲染

/**
 * 扫描渲染,顺时针方向逐渐渐变渲染 SweepGradient(float cx, float cy, @ColorInt int color0,int color1)
 * cx,cy 渐变中心座标
 * color0,color1:渐变开始结束颜色
 * colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变
 */
Shader shader  = new SweepGradient(200, 200,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        new float[]{0.5f, 0.3f,1});

8.4 BitmapShader位图渲染

/** 
* 位图渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
 * Bitmap:构造shader使用的bitmap
 * tileX:X轴方向的TileMode
 * tileY:Y轴方向的TileMode
            REPEAT, 绘制区域超过渲染区域的部分,重复排版
            CLAMP, 绘制区域超过渲染区域的部分,会以最后一个像素拉伸排版
            MIRROR, 绘制区域超过渲染区域的部分,镜像翻转排版
 */
Shader shader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);

8.5 ComposeShader组合渲染

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.flower);
Shader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

LinearGradient linearGradient = new LinearGradient(0, 0, 200, 200,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        null,
        Shader.TileMode.REPEAT);

Shader shader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
mPaint.setShader(shader);

9、ColorFilter

ColorFilter 这个类,它的名字已经足够解释它的作用:为绘制设置颜色过滤。颜色过滤的意思,就是为绘制的内容设置一个统一的过滤策略,然后Canvas.drawXXX() 方法会对每个像素都进行过滤后再绘制出来。

ColorFilter 并不直接使用,而是使用它的子类。它共有三个子类:LightingColorFilter、PorterDuffColorFilter 和 ColorMatrixColorFilter。

9.1 LightingColorFilter 光照效果

/**
 * 用来模拟简单的光照效果 LightingColorFilter(@ColorInt int mul, @ColorInt int add)
 * mul:和目标像素相乘,默认0xffffff
 * add:和目标像素相加,默认0x000000
 * R' = R * mul.R / 0xff + add.R
 * G' = G * mul.G / 0xff + add.G
 * B' = B * mul.B / 0xff + add.B
 */
ColorFilter filter = new LightingColorFilter(0x00ffff, 0x000000);

如果你想去掉原像素中的红色,可以把它的 mul 改为 0x00ffff。绿色加强,可以把它的 add 改为 0x003000。

9.2 PorterDuffColorFilter 混合滤镜

/**
 * 使用一个指定的颜色和一种指定的 PorterDuff.Mode 来与绘制对象进行合成
 * PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)
 * color: 指定的颜色
 * mode:指定的 Mode
 */
ColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);

9.3 ColorMatrixColorFilter

/**
 * 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵:
 * [ a, b, c, d, e,
 *   f, g, h, i, j,
 *   k, l, m, n, o,
 *   p, q, r, s, t ]
 * 对于颜色 [R, G, B, A] ,转换算法是这样的:
 *  R’ = a*R + b*G + c*B + d*A + e;
 *  G’ = f*R + g*G + h*B + i*A + j;
 *  B’ = k*R + l*G + m*B + n*A + o;
 *  A’ = p*R + q*G + r*B + s*A + t;
 */
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0.5f);
//colorMatrix.setRotate(0, 90);
//colorMatrix.setScale(0.5f,0.5f,0.5f,0.5f);
ColorFilter filter = new ColorMatrixColorFilter(colorMatrix)

ColorMatrix 有一些自带的方法可以做简单的转换,setSaturation(float sat) 来设置饱和度。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章