Android绘制:Shader

shader中文意思着色器,「着色器」不是 Android 独有的,它是图形领域里一个通用的概念,它和直接设置颜色的区别是,着色器设置的是一个颜色方案,或者说是一套着色规则。当设置了 Shader 之后,Paint 在绘制图形和文字时就不使用 setColor/ARGB() 设置的颜色了,而是使用 Shader 的方案中的颜色。

LinearGradient 线性渐变

可以设置两个端点和两个端点的颜色,从而使用这两种颜色的渐变来绘制颜色:
构造方法: LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)。

Shader shader = new LinearGradient(100,100,500,500, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
        paint.setShader(shader);
        canvas.drawCircle(300,300,200,paint);

Shader.TileMode

Shader的模型共有3个值

CLAMP

翻译为夹紧模式,会在端点之外延续端点处的颜色
看了下面的效果,就能理解。其实就是从在两个端点简渐变。

image.png
MIRROR

镜像模式
跟照镜子一样有个反的区域

image.png
REPEAT

重复模式
如名字一样

image.png

RadialGradient 辐射渐变

就是从中心向四周沿着半径渐变,翻译为辐射渐变

构造方法: RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)

参数: centerX centerY:辐射中心的坐标 radius:辐射半径 centerColor:辐射中心的颜色 edgeColor:辐射边缘的颜色 tileMode:辐射范围之外的着色模式。

 Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"),
                Color.parseColor("#2196F3"), Shader.TileMode.MIRROR);
        paint.setShader(shader);
        canvas.drawCircle(300,300,200,paint);
image.png

我们在设置的时候注意radius和TileMode。
如果Shader中的centerX、 centerY、radius三个参数与
canvas.drawCircle中的前三个参数一致的话,那么不管你怎么设置tileMode,效果都是一样的。都是上面的效果

只有当radius这个参数小于显示半径之后TitleMode才有效果:
我们将上面代码中的radius改成40,TileMode:CLMP

 Shader shader = new RadialGradient(300, 300, 40, Color.parseColor("#E91E63"),
                Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
        paint.setShader(shader);
        canvas.drawCircle(300,300,200,paint);
image.png

再将TileMode改为MIRROR

image.png

再将TileMode改为REPEAT

image.png

对比这三个效果,再结合上面介绍的,大家估计就能理解三种模式了。

SweepGradient 扫描渐变

构造方法: SweepGradient(float cx, float cy, int color0, int color1)

参数: cx cy :扫描的中心 color0:扫描的起始颜色 color1:扫描的终止颜色

 Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"),
                Color.parseColor("#2196F3"));
        paint.setShader(shader);
        canvas.drawCircle(300, 300, 200, paint);
image.png

BitmapShader

用 Bitmap 来着色,用 Bitmap 的像素来作为图形或文字的填充。

image.png

构造方法: BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

参数: bitmap:用来做模板的 Bitmap 对象 tileX:横向的 TileMode tileY:纵向的 TileMode。

 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mark_big);
        Shader shader = new BitmapShader(bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
        paint.setShader(shader);

        canvas.drawCircle(300,300,200,paint);

运行效果:

image.png

ComposeShader 混合着色器

// 第一个 Shader:头像的 Bitmap
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  
Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// 第二个 Shader:从上到下的线性渐变(由透明到黑色)
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);  
Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// ComposeShader:结合两个 Shader
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER);  
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 300, paint);  

注意:上面这段代码中我使用了两个 BitmapShader 来作为 ComposeShader() 的参数,而 ComposeShader() 在硬件加速下是不支持两个相同类型的 Shader 的,所以这里也需要关闭硬件加速才能看到效果
构造方法:ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

参数: shaderA, shaderB:两个相继使用的 Shader mode: 两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是 PorterDuff.Mode 。

PorterDuff.Mode PorterDuff.Mode 是用来指定两个图像共同绘制时的颜色策略的。它是一个 enum,不同的 Mode 可以指定不同的策略。「颜色策略」的意思,就是说把源图像绘制到目标图像处时应该怎样确定二者结合后的颜色,而对于 ComposeShader(shaderA, shaderB, mode) 这个具体的方法,就是指应该怎样把 shaderB 绘制在 shaderA 上来得到一个结合后的 Shader。 没有听说过 PorterDuff.Mode 的人,看到这里很可能依然会一头雾水:「什么怎么结合?就……两个图像一叠加,结合呗?还能怎么结合?」你还别说,还真的是有很多种策略来结合。 最符合直觉的结合策略,就是我在上面这个例子中使用的 Mode: SRC_OVER。它的算法非常直观:就像上面图中的那样,把源图像直接铺在目标图像上。不过,除了这种,其实还有一些其他的结合方式。例如如果我把上面例子中的参数 mode 改为 PorterDuff.Mode.DST_OUT,就会变成挖空效果:

image.png

而如果再把 mode 改为 PorterDuff.Mode.DST_IN,就会变成蒙版抠图效果:

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • 系列文章之 Android中自定义View(一)系列文章之 Android中自定义View(二)系列文章之 And...
    YoungerDev阅读 2,171评论 0 4
  • 听力输入是学习语言重要一环,在整个英语学习中起着承上启下的作用。 因为听力是口语的弹药库。婴儿学习语言的规律很简单...
    大威_Wayne阅读 3,756评论 4 139
  • 接触彩铅几个月,很有意思。胡乱画了些,以后有机会更新。先发一个。 先来张完成图
    孟德兄留步阅读 712评论 6 9
  • 每次的夜班,早上去查房的时候看到每个病人都好好的,心里总会念一句“菩萨保佑,所有的病人都活着”。心想着又少了一个夜...
    李苏珊阅读 306评论 0 0
  • 内容要点 沟通最大的问题在于,人们想当然地认为已经沟通了 什么是关键对话 每个人身上都会发生的和他人的互动行为,是...
    杨慧莉阅读 1,314评论 0 2