Paint
1. 概念
画笔,保存了绘制的 几何图形、文本和位图 的样式和颜色信息
2. 常用API
mPaint = new Paint();
mPaint.setColor(Color.RED); //设置颜色
mPaint.setARGB(255, 255, 255, 0); //设置Paint对象颜色,范围0~255
mPaint.setAlpha(200); //设置透明度
mPaint.setAntiAlias(true); //设置抗锯齿
mPaint.setStyle(Paint.Style.STROKE); //描边效果 FILL、STROKE、FILL_AND_STROKE
mPaint.setStrokeWidth(4); //描边宽度
mPaint.setStrokeCap(Paint.Cap.ROUND); //例图1:圆角风格 BUTT(default)、ROUND、SQUARE
mPaint.setStrokeJoin(Paint.Join.MITER); //例图2:拐角风格 MITER、ROUND、BEVEL
mPaint.setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)); //设置环形渲染器
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); //设置图层混合模式
mPaint.setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)); //设置颜色过滤器
mPaint.setFilterBitmap(true); //设置双线性过滤(例图3)
mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL)); //设置画笔这招滤镜,传入度数和样式
mPaint.setTextScaleX(2); //设置文本缩放倍数
mPaint.setTextSize(38); //设置字体大小
mPaint.setTextAlign(Paint.Align.LEFT); //设置对齐方式
mPaint.setUnderlineText(true); //设置下划线
String str = "Android高级工程师";
Rect rect = new Rect();
mPaint.getTextBounds(str, 0, str.length(), rect); //测量文本大小,将文本大小信息存放在rect中
mPaint.measureText(str); //获取文本的宽
mPaint.getFontMetrics(); //获取字体度量对象
例图1:setStrokeCap(Cap cap)
例图2:setStrokeJoin(Join join)
例图3:setFilterBitmap设置效果
重点概念:FontMetrics 字体的度量,是指对于指定字号的某种字体,在度量方面的各种属性,起描述参数包括
- baseline:字符基线
- top:字符最高点到baseline的最大距离
- bottom:字符最低点到baseline的最大距离
- ascent:字符最高点到baseline的推荐距离
- descent:字符最低点到baseline的推荐距离
-
leading:行间距,即前一行的descent与下一行的ascent之间的距离
参照理解FontMetrics各属性
3. 重点API解析:
3.1 setShader(Shader shader) 设置着色器(渲染器)对象,
一般使用的shader的几个子类
-
LinearGradient:线性渲染
/**
* LinearGradient (float x0, float y0, float x1, float y1,
@NonNull @ColorInt int colors[],
@Nullable float positions[], @NonNull TileMode tile)
* x0 y0 渐变起始点坐标
* x1 y1渐变结束点坐标
* color0 渐变开始点颜色
* color1 渐变技术颜色
* colors[] 渐变颜色数组
* positions[] 渐变位置数组,positions若不为null,需与colors数组length相同,表示在对应位置的颜色值,若为null,则线性渐变
* tile 当指定空间区域大于指定的渐变区域时,空白区域的颜色填充方法
*/
mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE}, null, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, 500, 500, mPaint); //效果1
mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE}, new float{0.5f, 1}, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, 500, 500, mPaint); //效果2
mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE, Color.GREEN}, new float{0, 0.7f, 1}, Shader.TileMode.REPEAT);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, 1000, 1000, mPaint); //效果3
LinearGradient设置效果1
LinearGradient设置效果2
LinearGradient设置效果3
-
RadialGradient:环形渲染
/**
* RadialGradient(float centerX, float centerY, float radius,
@NonNull @ColorInt int colors[], @Nullable float stops[],
@NonNull TileMode tileMode)
* centerX, centerY shader的中心坐标,开始渐变的坐标
* radius 渐变的半径
* centerColor, edgeColor 中心店渐变颜色,边界的渐变颜色
* colors[] 渐变颜色数组
* stops[] 渐变位置数组,类似线性渐变的positions数组,取值[0, 1],中心点为0,半径到达位置为1.0f
* tile 当指定空间区域大于指定的渐变区域时,空白区域的颜色填充方法
*/
mShader = new RadialGradient(250, 250, 250, new int[]{Color.GREEN, Color.YELLOW, Color.RED}, null, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawCircle(250, 250, 250, mPaint); //效果1
RadialGradient设置效果1
-
SweepGradient:扫描渲染
/**
* SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1)
* cx cy 渐变中心坐标
* color0 color1 渐变开始 结束颜色
* colors[] positions[] 类似LinearGradient中的作用,用于多颜色渐变
*/
mShader = new SweepGradient(250, 250, Color.RED, Color.GREEN);
mPaint.setShader(mShader);
canvas.drawCircle(250, 250, 250, mPaint); //效果1
SweepGradient设置效果1
-
BitmapShader:位图渲染
/**
* BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX,
@NonNull TileMode tileY)
* Bitmap 构造shader使用的bitmap
* tileX tileY X轴 Y轴方向上的TileMode(CLAMP,REPEAT,MIRROR)
* REPEAT 绘制区域超出渲染区域的部分,重复排版
* CLAMP 绘制区域超出渲染区域的部分,以最后一个像素拉伸排版
* MIRROR 绘制区域超出渲染区域的部分,镜像翻转排版
*/
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.beauty);
mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), mPaint); //效果1
canvas.drawRect(0, 0, 500, 500, mPaint); //效果2
mShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, 500, 500, mPaint); //效果3
mShader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, 500, 500, mPaint); //效果4
BitmapShader设置效果1
BitmapShader设置效果2
BitmapShader设置效果3
BitmapShader设置效果4
-
ComposeShader:组合渲染,例如LinearGradient+BitmapShader
BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
LinearGradient linearGradient = new LinearGradient(0, 0, 1000, 1600, new int[]{Color.RED, Color.GREEN, Color.BLUE}, null, Shader.TileMode.CLAMP);
mShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
mPaint.setShader(mShader);
canvas.drawCircle(250, 250, 250, mPaint); //效果1
ComposeShader设置效果1
重点概念:Xfermode以及PorterDuff.Mode图层混合模式
它将从绘制图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas中最终的像素颜色值。
注意:效果只作用于src源图像区域
共18种模式
Mode.CLEAR Mode.MULTIPLY Mode.SRC Mode.DST
Mode.SRC_OVER Mode.SRC_OUT Mode.SRC_IN Mode.SRC_ATOP
Mode.DST_OVER Mode.DST_OUT Mode.DST_IN Mode.DST_ATOP
Mode.XOR Mode.ADD Mode.DARKEN Mode.LIGHTEN
Mode.SCREEN Mode.OVERLAY
通过查看PorterDuff.java源码可看到Mode枚举各个类型的注释:
public enum Mode {
/**
* <p>\(\alpha_{out} = 0\)</p>
* <p>\(C_{out} = 0\)</p>
*/
CLEAR (0),
//alpha 混合后的alpha通道,out代表输出值(最终结果值)C代表颜色值
//src代表原图像,dst代表目标图像
//alpha与C共同决定混合后的效果
...
}
举例 自定义View XfermodeView
官方demo 地址
public class XfermodeView extends View{
private Paint mPaint;
private int mWidth, mHeight;
public XfermodeView(Context context){
this(context, null);
}
public XfermodeView(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protect void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
}
@Override
protect void onDraw(Canvas canvas){
super.onDraw(canvas);
//Xfermode 几个用处
//1.ComposerShader 构造方法需传入一个Xfermode参数
//2.画笔Paint.setXfermode()
//3.PorterDuffColorFilter
//图层混合前,要禁止硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
//离屏绘制
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
setBackgroundColor(Color.GRAY);
//目标图
canvas.drawBitmap(createRectBitmap(mWidth, mHeight), 0, 0, mPaint);
//设置混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//源图,重叠区域右下角部分
canvas.drawBitmap(createCircleBitmap(mWidth, mHeight), 0, 0, mPaint);
//清楚混合模式
mPaint.setXfermode(null);
canvas.restoreToCount(layerId)
}
//画矩形Dst
public Bitmap createRectBitmap(int width, int height){
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dstPaint.setColor(0xFF66AAFF);
canvas.drawRect(new Rect(width/20, height/3, width * 2/3, height*19/20), dstPaint);
return bitmap;
}
//画圆形Src
public Bitmap createCircleBitmap(int width, int height){
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
srcPaint.setColor(0xFFFFCC44);
canvas.drawCircle(width*2/3, height/3, height/4, srcPaint);
return bitmap;
}
}
运行效果1
重点概念:离屏绘制
通过使用离屏绘制缓冲,把要绘制的内容单独绘制在缓冲层,保证Xfermode的使用不会出现错误的结果
使用离屏缓冲有两种方式
1. Canvas.saveLayer()
//可以做短时的离屏缓冲,在绘制之前保存,绘制之后恢复。
int saveId = canvas.saveLayer(0, 0, width, height, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(rectBitmap, 0, 0, paint); //画方
paint.setXfermode(xfermode); //设置Xfermode
canvas.drawBitmap(circleBitmap, 0, 0, paint); //画圆
paint.setXfermode(null); //用户及时清除Xfermode
canvas.restoreToCount(saveId);
2. View.setLayerType()
//直接把整个View都绘制在离屏缓冲中
setLayerType(LAYER_TYPE_HARDWARE); 使用GPU来缓冲
setLayerType(LAYER_TYPE_SOFTWARE); 使用一个Bitmap来缓冲
3.2 setColorFilter(ColorFilter colorFilter) 设置颜色过滤
一般使用ColorFilter三个子类
-
LightingColorFilter:光照效果
/**
* LightingColorFilter(@ColorInt int mul, @ColorInt int add)
* mul 和 add 都是和颜色值格式相同的int值,其中mul用来和目标像素相乘,add用来和目标像素相加
* R' = R * mul.R / 0xff + add.R
* G' = G * mul.G / 0xff + add.G
* B' = B * mul.B / 0xff + add.B
*/
ColorFilter lighting = new LightingColorFilter(0xffffff, 0x000000); //原图效果
ColorFilter lighting = new LightingColorFilter(0x00ffff, 0x000000); //去除红色
paint.setColorFilter(lighting);
canvas.drawBitmap(bitmap, 0, 0, paint);
-
PorterDuffColorFilter:制定一个颜色和一种PorterDuff.Mode与绘制对象进行合成
/**
* PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)
* color 具体的颜色值,例如Color.RED
* mode 指定PorterDuff.Mode混合模式
* 与之前说的paint.setXfermode()设置图层混合模式,是指图片与图片进行图层混合,此处只能进行颜色与图片进行图层混合。
*/
PorterDuffColorFilter porterDuffColorFilter =
new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN);
paint.setColorFilter(porterDuffColorFilter);
canvas.drawBitmap(mBitmap, 100, 0, paint);
-
ColorMatrixColorFilter:使用一个ColorMatrix来对颜色进行处理
/**
* ColorMatrixColorFilter(@NonNull float[] colorMatrix)
* colorMatrix 4行5列矩阵数组 第5列是偏移量
*
* ColorMatrixColorFilter(@NonNull ColorMatrix matrix)
* matrix
*/
float[] colorMatrix = {
1, 0, 0, 0, 0, //red
0, 1, 0, 0, 0, //green
0, 0, 1, 0, 0, //blue
0, 0, 0, 1, 0, //alpha
}
mColorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
mPaint.setColorFilter(mColorMatrixColorFilter);
canvas.drawBitmap(mBitmap, 100, 0, mPaint);
ColorMatrix cm = new ColorMatrix();
//亮度调节
cm.setScale(1, 1, 1, 1); //分别是红绿蓝透明的调节系数
//饱和度调节 0-无色彩 1-默认效果 >1饱和度加强
cm.setSaturation(1);
//色度调节 axis-0 红色的旋转角度 axis-1 绿色的旋转角度 axis-2 蓝色旋转角度
c.setRotate(1, 45)
mColorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
mPaint.setColorFilter(mColorMatrixColorFilter);
canvas.drawBitmap(mBitmap, 100, 0, mPaint);
重点概念 色彩矩阵
在Android中,系统使用一个颜色矩阵 ColorMatrix,来处理图像的色彩效果。对于图像的每个像素点,都有一个颜色分量矩阵来保存颜色的TGBA值(下图矩阵C),Android中的颜色矩阵就是一个4*5的数字矩阵,它用来对图片的色彩进行处理(下图矩阵A)
颜色矩阵
网友评论