canvas教程

Android中Canvas绘图之Shader使用图文详解(2)(2)

字号+ 作者:H5之家 来源:H5之家 2017-03-22 10:00 我要评论( )

上面的图片是透明的,不过图片中有个心形图案是白色,不透明。我想让渐变颜色只填充上图中的形区域,透明部分不填充,颜色从绿色渐变到蓝色,渐变方向从左上角到右下角。我们不用ComposeShader即可实现上述效果,代

上面的图片是透明的,不过图片中有个心形图案是白色,不透明。我想让渐变颜色只填充上图中的形区域,透明部分不填充,颜色从绿色渐变到蓝色,渐变方向从左上角到右下角。我们不用ComposeShader即可实现上述效果,代码如下所示:

int bitmapWidth = bitmap.getWidth(); int bitmapHeight = bitmap.getHeight(); //将绘制代码放入到canvas.saveLayer()和canvas.restore()之间 canvas.saveLayer(0, 0, bitmapWidth, bitmapHeight, null, Canvas.ALL_SAVE_FLAG); //创建BitmapShader,用以绘制形 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //将BitmapShader作为画笔paint绘图所使用的shader paint.setShader(bitmapShader); //用BitmapShader绘制矩形 canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint); //将画笔的Xfermode设置为PorterDuff.Mode.MULTIPLY模式 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); //创建LinearGradient,用以产生从左上角到右下角的颜色渐变效果 LinearGradient linearGradient = new LinearGradient(0, 0, bitmapWidth, bitmapHeight, Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP); //将创建LinearGradient作为画笔paint绘图所使用的shader paint.setShader(linearGradient); //用LinearGradient绘制矩形 canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint); //最后将画笔去除掉Xfermode paint.setXfermode(null); canvas.restore();

效果如下所示:

如果认真读过博文 《Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解》 的话,我相信大家应该能明白上图出现的原因。

此处我们还是一起分析一下代码的执行过程。

  • 我们的图片中间的形区域是纯白色,该区域的像素颜色值ARGB分量是(255,255,255,255)。形区域以外的区域是纯透明的,该区域的像素颜色值ARGB分量是(0,0,0,0)。

  • 为了使用Xfermode,我们将绘图的代码放到了canvas.saveLayer()和canvas.restore()之间,对此有疑问的同学可以参见我上述提到的博文。canvas.saveLayer()会创建一个新的绘图图层,而且该图层是全透明的,我们后面的代码都是绘制到这个图层上,而不是直接绘制到Canvas上。

  • 我们用上述Bitmap创建了一个BitmapShader,并将其绑定到画笔Paint中。当我们用canvas.drawRect()绘制矩形时,就会用该BitmapShader填充,此时的效果应该是在新创建的layer上绘制了一个白色的心形。

  • 然后我们创建了一个PorterDuffXfermode的实例,并通过paint.setXfermode()将其绑定到画笔paint上。其中PorterDuffXfermode的mode类型为MULTIPLY。MULTIPLY的意思是将源像素的ARGB四个分量分别与目标像素对应的ARGB四个分量相乘,将相乘的结果作为混合后的像素。此处进行相乘时,ARGB四个分量都已经从[0, 255]的区间归一化到[0.0, 1.0]的区间。

  • 然后我们创建了一个LinearGradient,用以实现颜色线性渐变效果。颜色从左上角的绿色渐变到右下角的蓝色。然后我们通过paint.setShader()方法将其绑定到画笔paint的shader上。

  • 后面我们再次调用canvas.drawRect()绘制同样大小的一个矩形。在绘制时,我们的画笔已经同时绑定了Xfermode和Shader。首先canvas会用LinearGradient绘制一个具有渐变色的矩形区域。然后根据画笔设置的PorterDuff.Mode.MULTIPLY类型,将那些由渐变色填充的矩形区域中的像素与我们在第3步中绘制的心形图片中的像素颜色进行相乘混合。渐变色填充的矩形区域中的像素是源像素,第3步中绘制的心形图片中的像素是目标像素。目标像素中形区域是纯白色的,其像素颜色是(255,255,255,255),归一化后的颜色是(1,1,1,1),对应位置的源像素中的ARGB颜色分量与其相乘,最终的颜色还是源像素的颜色,即心形区域被源像素着上了渐变色。目标像素中形区域以外的颜色是纯透明的,颜色是(0,0,0,0),对应位置的源像素中的ARGB颜色分量与其相乘,最终的颜色还是目标像素中的(0,0,0,0),即心形区域以外没有被着色,依旧呈现透明色。

  • 最后通过调用canvas.restore()方法将新创建的layer绘制到Canvas上去,这样我们就看到最终的效果了。

  • 下面我们看看如和用ComposeShader实现上述效果,代码如下所示:

    int bitmapWidth = bitmap.getWidth(); int bitmapHeight = bitmap.getHeight(); //创建BitmapShader,用以绘制形 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //创建LinearGradient,用以产生从左上角到右下角的颜色渐变效果 LinearGradient linearGradient = new LinearGradient(0, 0, bitmapWidth, bitmapHeight, Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP); //bitmapShader对应目标像素,linearGradient对应源像素,像素颜色混合采用MULTIPLY模式 ComposeShader composeShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY); //将组合的composeShader作为画笔paint绘图所使用的shader paint.setShader(composeShader); //用composeShader绘制矩形区域 canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint);

    用ComposeShader实现的效果与上图相同,我就不再贴图了。我们可以看到,使用ComposeShader之后,实现相同的效果时,代码量明显减少了,而且我们也不需要将绘图代码放到canvas.saveLayer()和canvas.restore()之间了。

    根据上面的示例,我们可以得出如下结论:

    假设我们定义了两个Shader的变量,shaderA和shaderB,并分别对这两个Shader进行了实例化。

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    网友点评
    t