我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader(eg:mPaint.setShader(shader)),
这样就可以绘制出多彩的图形。那么Shader是什么呢?,Shader就是着色器的意思。我们可以这样理解,
Canvas中的各种drawXXX方法 eg: canvas.drawCircle()。
定义了图形的形状,画笔中的Shader则定义了图形的着色、外观,二者结合到一起就决定了最终Canvas绘制的被色彩填充的图形的样子。
类android.graphics.Shader
有五个子类,分别是:BitmapShader、LinearGradient、RadialGradient、SweepGradient和ComposeShader,下面主要对SweepGradient,ComposeShader类的使用详细说明。
SweepGradient可以用来创建雷达扫描渐变效果,具体来说颜色是围绕中心点360度顺时针旋转的。
1./** * A Shader that draws a sweep gradient around a center point. * * @param cx The x-coordinate of the center X轴中心坐标 * @param cy The y-coordinate of the center Y轴中心坐标 * @param colors The colors to be distributed between around the center. * There must be at least 2 colors in the array. * @param positions May be NULL. The relative position of * each corresponding color in the colors array, beginning * with 0 and ending with 1.0. If the values are not * monotonic, the drawing may produce unexpected results. * If positions is NULL, then the colors are automatically * spaced evenly. */ public SweepGradient(float cx, float cy, @NonNull @ColorInt int colors[], @Nullable float positions[]) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException( "color and position arrays must be of equal length"); } mType = TYPE_COLORS_AND_POSITIONS; mCx = cx; mCy = cy; mColors = colors.clone(); mPositions = positions != null ? positions.clone() : null; } 2. /** * A Shader that draws a sweep gradient around a center point. * * @param cx The x-coordinate of the center X轴中心坐标 * @param cy The y-coordinate of the center Y轴中心坐标 * @param color0 The color to use at the start of the sweep :在扫描开始时使用的颜色 * @param color1 The color to use at the end of the sweep 在扫描结束时使用的颜色 */ public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { mType = TYPE_COLOR_START_AND_COLOR_END; mCx = cx; mCy = cy; mColor0 = color0; mColor1 = color1; mColors = null; mPositions = null; } |
private int mWidth, mHeight; /** * 5个圆 */ private float[] pots = {0.05f, 0.1f, 0.15f, 0.2f, 0.25f}; /** * 扫描渲染shader */ private Shader scanShader; /** * 旋转需要的矩阵 */ private Matrix matrix = new Matrix(); /** * 扫描速度 */ private int scanSpeed = 5; /** * 扫描旋转的角度 */ private int scanAngle; /** * 画圆用到的paint */ private Paint mPaintCircle; /** * 扫描用到的paint */ private Paint mPaintRadar; |
public RadarView(Context context) { super(context); // 画圆用到的paint mPaintCircle = new Paint(); // 描边 mPaintCircle.setStyle(Paint.Style.STROKE); // 宽度 mPaintCircle.setStrokeWidth(1); // 透明度 mPaintCircle.setAlpha(100); // 抗锯齿 mPaintCircle.setAntiAlias(true); // 设置颜色 亮钢兰色 mPaintCircle.setColor(Color.parseColor("#B0C4DE")); // 扫描用到的paint mPaintRadar = new Paint(); // 填充 mPaintRadar.setStyle(Paint.Style.FILL_AND_STROKE); mPaintRadar.setAntiAlias(true); post(run);
} private Runnable run = new Runnable() { @Override public void run() { // 旋转角度 对360取余 scanAngle = (scanAngle + scanSpeed) % 360; // 旋转矩阵 matrix.postRotate(scanSpeed, mWidth / 2, mHeight / 2); // 通知view重绘 invalidate(); // 调用自身 重复绘制 postDelayed(run, 50); } }; |
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 取屏幕的宽高 mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); mWidth = mHeight = Math.min(mWidth, mHeight); } |
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < pots.length; i++) { canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth * pots[i], mPaintCircle); } canvas.save(); scanShader = new SweepGradient(mWidth / 2, mHeight / 2, new int[]{Color.TRANSPARENT, Color.parseColor("#84B5CA")}, null); // 设置着色器 mPaintRadar.setShader(scanShader); canvas.concat(matrix); canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth * pots[4], mPaintRadar); canvas.restore(); } |
ComposeShader,顾名思义,就是混合Shader的意思,它可以将两个Shader按照一定的Xfermode组合起来。
定义:/** A subclass of shader that returns the composition of two other shaders, combined by an {@link android.graphics.Xfermode} subclass. 它返回另外两个着色器的组合,再加上Xfermode */ public class ComposeShader extends Shader {..... /** * Xfermode is the base class for objects that are called to implement custom * "transfer-modes" in the drawing pipeline. The static function Create(Modes) * can be called to return an instance of any of the predefined subclasses as * specified in the Modes enum. When an Xfermode is assigned to an Paint, then * objects drawn with that paint have the xfermode applied. */ public class Xfermode { static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt; int porterDuffMode = DEFAULT; } 1./** * Create a new compose shader, given shaders A, B, and a combining PorterDuff mode. * When the mode is applied, it will be given the result from shader A as its * "dst", and the result from shader B as its "src". * * @param shaderA The colors from this shader are seen as the "dst" by the mode * @param shaderB The colors from this shader are seen as the "src" by the mode * @param mode The PorterDuff mode that combines the colors from the two shaders. */ public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull PorterDuff.Mode mode) { this(shaderA, shaderB, mode.nativeInt); }2. private ComposeShader(Shader shaderA, Shader shaderB, int nativeMode) { if (shaderA == null || shaderB == null) { throw new IllegalArgumentException("Shader parameters must not be null"); } mShaderA = shaderA; mShaderB = shaderB; mPorterDuffMode = nativeMode; } |
需要图片:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
/**
* 用ComposeShader即可实现心形图渐变效果
* 创建BitmapShader */ Bitmap mBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.heart_img)).getBitmap(); BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //创建LinearGradient,用以产生从左上角到右下角的颜色渐变效果 LinearGradient linearGradient = new LinearGradient(0, 0, mWidth, mHeight, Color.RED, Color.BLUE, Shader.TileMode.CLAMP); //bitmapShader对应目标像素,linearGradient对应源像素,像素颜色混合采用MULTIPLY模式 ComposeShader composeShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY); //将组合的composeShader作为画笔paint绘图所使用的shader mPaint.setShader(composeShader); //用composeShader绘制矩形区域 canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), mPaint); } |
TitleMode.CLAMP | 拉伸最后一个像素去铺满剩下的地方(CLAMP表示,当所画图形的尺寸大于Bitmap的尺寸的时候,会用Bitmap四边的颜色填充剩余空间) |
TitleMode.MIRROR | 通过镜像翻转铺剩下的地方(与REPEAT类似,当绘制的图形尺寸大于Bitmap尺寸时,MIRROR也会用Bitmap重复平铺整个绘图区域,与REPEAT不同的是,两个相邻的Bitmap互为镜像) |
TitleMode.REPEAT | 重复图片平铺整个画面(设置壁纸)在图片平铺和显示区域大小不符的情况下进行扩展渲染(REPEAT表示,当我们绘制的图形尺寸大于Bitmap尺寸时,会用Bitmap重复平铺整个绘制的区域。) |
相关阅读:
Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解
Android中Canvas绘图基础详解(附源码下载)
我的Android博文整理汇总
Android中Canvas绘图之Shader使用图文详解