在自定义控件中Paint和Canvas的重要性就不用了多说了,本篇文章将记录学习内容。
Paint的基础使用就不记录了,这里记录下渲染、滤镜和Xfermode。
先来看看渲染,渲染的主要形式是以Shader 着色器来实现。看下例子:
/**
* TileMode.CLAMP 拉伸最后一个像素去铺满剩下的地方
* TileMode.MIRROR 通过镜像翻转铺满剩下的地方。
* TileMode.REPEAT 重复图片平铺整个画面(电脑设置壁纸)
* 在图片和显示区域大小不符的情况进行扩充渲染
*/
/**
* 位图渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
* Bitmap:构造shader使用的bitmap
* tileX:X轴方向的TileMode
* tileY:Y轴方向的TileMode
*/
BitmapShader bitmapShader =new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(bitmapShader);
例子中使用位图渲染,接下来记录下其他的几种渲染方式:
/**线性渲染
* x0, y0, 起始点
* x1, y1, 结束点
* int[] mColors, 中间依次要出现的几个颜色
* float[] positions 位置数组,position的取值范围[0,1],作用是指定几个颜色分别放置在那个位置上,
* 如果传null,渐变就线性变化。
* tile 用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法
*/
LinearGradient linearGradient =new LinearGradient(0, 0, 500, 600, mColors,mFloats , Shader.TileMode.REPEAT);
/**
* 扫描渲染
* cx,cy 渐变中心坐标
* color0,color1:渐变开始结束颜色
* colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变
*/
SweepGradient sweepGradient =new SweepGradient(400, 400, mColors, null);
/**
* 组合渲染,
* ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)
* ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)
* shaderA,shaderB:要混合的两种shader
* Xfermode mode: 组合两种shader颜色的模式
* PorterDuff.Mode mode: 组合两种shader颜色的模式
*/
ComposeShader composeShader =new ComposeShader(sweepGradient, linearGradient, PorterDuff.Mode.SRC);
渲染中最常用的是组合渲染,其中用到PorterDuff.Mode这里就不记录了附上官网链接方便点击查看。渲染就到这里接下来看看滤镜:
滤镜其实是对图像颜色进行调整。
颜色模式分为:RBG模式、CMYK模式、HSB模式、Lab模式、位图模式、灰度模式、索引模式、颜色模式、双色调模式、多通道模式。
颜色模式的不同颜色的通道也不同。
这里介绍常用的ARGB模式 A为透明通道R红色G为绿色B为蓝色 这些通道的值越大像素点所占比颜色就越多。比如A通道值越大就越透明。
颜色矩阵:android中可以通过颜色矩阵 ColorMatrix 方便的操作颜色,可以用来方面的修改图片中RGBA各分量的值,一般以是一个5x4 的矩阵。
计算方式为: 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 colorMartrix1 =new ColorMatrix(new float[]{
1, 0,0,0,0,
0,1,0,0,100,
0,0,1,0,0,
0,0,0,1,0,
});
//反相效果 -- 底片效果
ColorMatrix colorMartrix2 =new ColorMatrix(new float[]{
-1, 0,0,0,255,
0,-1,0,0,255,
0,0,-1,0,255,
0,0,0,1,0,
});
// 缩放运算---乘法 -- 颜色增强
ColorMatrix colorMartrix3 =new ColorMatrix(new float[]{
1.2f, 0,0,0,0,
0,1.2f,0,0,0,
0,0,1.2f,0,0,
0,0,0,1.2f,0,
});
/** 黑白照片
*是将我们的三通道变为单通道的灰度模式
*去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,
*同时为了保证图像亮度不变,同一个通道里的R+G+B =1
*/
ColorMatrix colorMartrix4 =new ColorMatrix(new float[]{
0.213f, 0.715f,0.072f,0,0,
0.213f, 0.715f,0.072f,0,0,
0.213f, 0.715f,0.072f,0,0,
0,0,0,1,0,
});
// 发色效果---(比如红色和绿色交换)
ColorMatrix colorMartrix5 =new ColorMatrix(new float[]{
1,0,0,0,0,
0, 0,1,0,0,
0,1,0,0,0,
0,0,0,0.5F,0,
});
// 复古效果
ColorMatrix colorMartrix6 =new ColorMatrix(new float[]{
1/2f,1/2f,1/2f,0,0,
1/3f, 1/3f,1/3f,0,0,
1/4f,1/4f,1/4f,0,0,
0,0,0,1,0,
});
// 颜色通道过滤
//两个矩阵
//本身颜色矩阵 A
//过滤矩阵 c
//a*c=out color
ColorMatrix colorMartrix7 =new ColorMatrix(new float[]{
1.3F,0,0,0,0,
0,1.3F,0,0,0,
0,0,1.3F,0,0,
0,0,0,1,0,
});
setMaskFilter方法为设置滤镜这里记录几个例子:
/**
* 模糊遮罩效果
* @param radius 阴影的半径
* @param style NORMOL -- 整个图像都被模糊掉
* SOLID -- 图像边界外产生一层与Paint颜色一致阴影效果,不影响图像的本身
* OUTER -- 图像边界外产生一层阴影,并且将图像变成透明效果
* INNER -- 在图像内部边沿产生模糊效果
* @return
*/
mPaint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER));
/**
* 浮雕遮罩效果(绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样(在设计软件中类似的效果称之为斜面浮雕))
* @param direction 指定光源的位置,长度为xxx的数组标量[x,y,z]
* @param ambient 环境光的因子 (0~1),越接近0,环境光越暗
* @param specular 镜面反射系数 越接近0,镜面反射越强
* @param blurRadius 模糊半径 值越大,模糊效果越明显
*/
mPaint.setMaskFilter(new EmbossMaskFilter(new float[]{1,1,1},0.2f,60,80));
需要注意的是这些特效是需要关闭硬件加速的:setLayerType(View.LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
如果不关闭则看不到这些效果。
接下来记录下Xfermode:该Api可以完成图像组合的效果(通过两张图片组合,生成新的图片)
组合模式使用PorterDuff.Mode详细点击查看。
其子类有3个PixelXorXfermode、AvoidXfermode、PorterDuffXfermode其中前两个已经过时不推荐使用就不做记录了,看看PorterDuffXfermode的例子:
public class Xfermodeextends View {
private PaintmPaint;
float mTextSize =25;
float mItemSize =0;
float mItemHorizontalOffset =0;
float mItemVerticalOffset =0;
float mCircleRadius =0;
float mRectSize =0;
int mCircleColor =0xffffcc44;//黄色
int mRectColor =0xff66aaff;//蓝色
private static final android.graphics.Xfermode[]sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
new PorterDuffXfermode(PorterDuff.Mode.SRC),
new PorterDuffXfermode(PorterDuff.Mode.DST),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
new PorterDuffXfermode(PorterDuff.Mode.XOR),
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
};
private static final String[]sLabels = {
"Clear", "Src", "Dst", "SrcOver",
"DstOver", "SrcIn", "DstIn", "SrcOut",
"DstOut", "SrcATop", "DstATop", "Xor",
"Darken", "Lighten", "Multiply", "Screen"
};
public Xfermode(Context context) {
super(context);
init(null, 0);
}
public Xfermode(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public Xfermode(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int defStyle) {
if(Build.VERSION.SDK_INT >=11){
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
mPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextSize(mTextSize);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setStrokeWidth(2);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mItemSize = w /4.5f;
mItemHorizontalOffset =mItemSize /6;
mItemVerticalOffset =mItemSize *0.426f;
mCircleRadius =mItemSize /3;
mRectSize =mItemSize *0.6f;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
for (int row =0; row <4; row++) {
for (int column =0; column <4; column++) {
canvas.save();
int layer = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
mPaint.setXfermode(null);
int index = row *4 + column;
float translateX = (mItemSize +mItemHorizontalOffset) * column;
float translateY = (mItemSize +mItemVerticalOffset) * row;
canvas.translate(translateX, translateY);
//画文字
String text =sLabels[index];
mPaint.setColor(Color.BLACK);
float textXOffset =mItemSize /2;
float textYOffset =mTextSize + (mItemVerticalOffset -mTextSize) /2;
canvas.drawText(text, textXOffset, textYOffset, mPaint);
canvas.translate(0, mItemVerticalOffset);
//画边框
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0xff000000);
canvas.drawRect(2, 2, mItemSize -2, mItemSize -2, mPaint);
mPaint.setStyle(Paint.Style.FILL);
//画圆
mPaint.setColor(mCircleColor);
float left =mCircleRadius +3;
float top =mCircleRadius +3;
canvas.drawCircle(left, top, mCircleRadius, mPaint);
mPaint.setXfermode(sModes[index]);
//画矩形
mPaint.setColor(mRectColor);
float rectRight =mCircleRadius +mRectSize;
float rectBottom =mCircleRadius +mRectSize;
canvas.drawRect(left, top, rectRight, rectBottom, mPaint);
mPaint.setXfermode(null);
//canvas.restore();
canvas.restoreToCount(layer);
}
}
}
}
这个例子包含了所有例子。到这里paint就结束了。
作者:Dean_Xu
原创博客,请注明转载处....