鸿蒙开发-想让绘制更好看?渐变、阴影和混合模式
上一篇我们学了 Canvas + Brush + Pen 的基础用法——画矩形、画圆、填颜色、描边。但如果你真的在做一个绘画 APP,光有这些是不够的。你还需要渐变色、半透明、抗锯齿、阴影……
今天我们来深入看看 Brush 和 Pen 的进阶功能。
下面是 Brush 和 Pen 进阶功能的整体结构:
抗锯齿:让边缘更平滑
你有没有注意过,画一个圆的时候,边缘可能会有锯齿感——就像一排阶梯一样。这是因为屏幕是由像素点组成的,斜线和曲线在像素网格上不可能完美平滑。
抗锯齿(Anti-Aliasing)的原理很简单:在边缘处用半透明的像素做过渡,让阶梯感变弱。Brush 和 Pen 都支持开启抗锯齿:
constbrush=newdrawing.Brush();brush.setAntiAlias(true);// 开启抗锯齿constpen=newdrawing.Pen();pen.setAntiAlias(true);// 开启抗锯齿开启后,图形的边缘会更平滑,但可能会稍微模糊一点。一般情况下建议开启,除非你在做像素画那种需要锐利边缘的风格。
透明度:做出层次感
brush.setAlpha(128);// 半透明pen.setAlpha(64);// 更透明取值范围[0, 255],0 完全透明(看不见),255 完全不透明。
透明度能做什么?很多效果都离不开它:
- 半透明的色块叠加,做出"磨砂玻璃"效果
- 多层半透明图形叠加,做出深度感
- 淡入淡出动画(通过动态改变 alpha 值)
渐变色:不只是纯色
纯色太平淡了?用ShaderEffect可以做出渐变效果。ShaderEffect 支持三种渐变:
线性渐变
从一个点到另一个点,颜色平滑过渡:
constshaderEffect=drawing.ShaderEffect.createLinearGradient({x:0,y:0},// 起点{x:300,y:0},// 终点[0xFFFF0000,0xFF0000FF],// 红色到蓝色drawing.TileMode.CLAMP// 平铺模式);brush.setShaderEffect(shaderEffect);canvas.attachBrush(brush);canvas.drawRect(0,0,300,200);canvas.detachBrush();这段代码画了一个从左到右、红到蓝渐变的矩形。
colors数组里放的是 32 位 ARGB 颜色值。格式是0xAARRGGBB,比如0xFFFF0000是不透明的红色,0xFF0000FF是不透明的蓝色。
TileMode控制渐变超出范围后怎么处理:
CLAMP:用边缘颜色填充剩余区域REPEAT:重复渐变MIRROR:镜像重复DECAL:只在原始范围内渲染
径向渐变
从圆心向外扩散的渐变:
constshaderEffect=drawing.ShaderEffect.createRadialGradient({x:150,y:100},// 圆心100,// 半径[0xFFFF0000,0xFF00FF00],// 红色到绿色drawing.TileMode.CLAMP);brush.setShaderEffect(shaderEffect);这种渐变就像阳光从中心向外扩散,中心是红色,边缘是绿色。适合做按钮的"发光"效果或者背景的"聚光灯"效果。
扫描渐变
像雷达扫描一样,绕着圆心旋转的渐变:
constshaderEffect=drawing.ShaderEffect.createSweepGradient({x:150,y:100},// 圆心[0xFFFF0000,0xFF0000FF,0xFF00FF00],// 红→蓝→绿drawing.TileMode.CLAMP,0,// 起始角度360// 结束角度);brush.setShaderEffect(shaderEffect);适合做圆形进度条、色轮选择器之类的 UI。
面对三种渐变类型,如何选择?可以参考下面的流程:
渐变也能用在 Pen 上
不只是 Brush,Pen 也支持 ShaderEffect:
constpen=newdrawing.Pen();pen.setStrokeWidth(10);pen.setShaderEffect(shaderEffect);canvas.attachPen(pen);canvas.drawLine(0,0,300,200);// 渐变色的线条canvas.detachPen();一条从红到蓝渐变的线,是不是很酷?
阴影:给文字加立体感
ShadowLayer可以给绘制内容加阴影。不过目前只在绘制文字时生效,图形暂时不支持。
import{common2D,drawing}from'@kit.ArkGraphics2D';// 创建阴影层:模糊半径、x偏移、y偏移、颜色letcolor:common2D.Color={alpha:0xFF,red:0x00,green:0x00,blue:0x00};letshadowLayer=drawing.ShadowLayer.create(3,-3,3,color);constbrush=newdrawing.Brush();brush.setShadowLayer(shadowLayer);canvas.attachBrush(brush);// 在这里绘制文字...canvas.detachBrush();create的四个参数:
blurRadius:阴影的模糊半径,值越大阴影越"散"x:阴影在 x 方向的偏移,正值向右,负值向左y:阴影在 y 方向的偏移,正值向下,负值向上color:阴影的颜色
比如你想做一个"文字投影"效果:create(5, 2, 2, 黑色)就是向右下方偏移 2 像素、模糊半径 5 的黑色阴影。
混合模式:颜色叠加的魔法
当两个图形重叠时,重叠区域的颜色怎么算?这就是混合模式(BlendMode)决定的。
brush.setBlendMode(drawing.BlendMode.SRC_OVER);// 默认模式SRC_OVER是默认模式——后画的盖在先画的上面。其他常见的混合模式还有:
SRC:只显示后画的,忽略先画的DST_OVER:后画的在先画的下面SRC_IN:只显示后画的和先画的重叠部分(用后画的颜色)DST_IN:只显示重叠部分(用先画的颜色)MULTIPLY:正片叠底,颜色相乘,重叠区域变暗SCREEN:滤色,重叠区域变亮
混合模式在做"图层特效"时很有用。比如你想做一个"叠加"效果,就用MULTIPLY;想做"发光"效果,就用SCREEN。
颜色滤波器:调整颜色
ColorFilter可以对颜色做变换,比如转灰度、调色相等:
letcolorFilter=drawing.ColorFilter.createSRGBGammaToLinear();brush.setColorFilter(colorFilter);ColorFilter提供了多种创建方式:
createSRGBGammaToLinear():sRGB gamma 转线性createLinearToSRGBGamma():线性转 sRGB gammacreateFromMatrix(colorMatrix):自定义颜色矩阵(和 effectKit 的 setColorMatrix 类似)
颜色滤波器会作用在所有绘制的颜色上,相当于给整个画面加了一层"颜色滤镜"。
图像滤波器:模糊和锐化
ImageFilter可以对绘制结果做图像处理,比如模糊:
letimageFilter=drawing.ImageFilter.createBlur(5,5,drawing.TileMode.CLAMP,null);brush.setImageFilter(imageFilter);和effectKit的 blur 不同,这里的模糊是实时的——每次绘制都会应用。适合做"毛玻璃"效果的 UI 元素。
Pen 也支持 ImageFilter:
letcolorFilter=drawing.ColorFilter.createSRGBGammaToLinear();letimgFilter=drawing.ImageFilter.createFromColorFilter(colorFilter);pen.setImageFilter(imgFilter);完整示例:渐变色卡片
来一个实际的例子——画一个带渐变背景和圆角的卡片:
import{RenderNode}from'@kit.ArkUI';import{common2D,drawing}from'@kit.ArkGraphics2D';classCardRenderNodeextendsRenderNode{draw(context:DrawContext){constcanvas=context.canvas;// 渐变背景:从左上到右下的蓝紫渐变constbrush=newdrawing.Brush();constgradient=drawing.ShaderEffect.createLinearGradient({x:0,y:0},{x:300,y:200},[0xFF6200EE,0xFFBB86FC],drawing.TileMode.CLAMP);brush.setShaderEffect(gradient);brush.setAntiAlias(true);canvas.attachBrush(brush);// 画圆角矩形constroundRect=newdrawing.RoundRect({left:20,top:20,right:320,bottom:220},16,16);canvas.drawRoundRect(roundRect);canvas.detachBrush();}}这段代码画了一个从深紫到浅紫渐变的圆角卡片。渐变 + 圆角 + 抗锯齿,三者组合起来就已经很好看了。
几个实用技巧
1. ShaderEffect 设为 null 可以清除
brush.setShaderEffect(null);// 清除渐变,回到纯色模式Brush 和 Pen 的所有"设置"方法都支持传null来清除效果(setShaderEffect、setColorFilter、setImageFilter、setShadowLayer、setPathEffect)。
2. 拷贝构造可以复用样式
如果你要画很多相同样式的图形,可以用拷贝构造函数避免重复设置:
constbrush=newdrawing.Brush();brush.setColor(255,255,0,0);brush.setAntiAlias(true);// 拷贝一份,两个 Brush 样式一样constbrush2=newdrawing.Brush(brush);Pen 也一样:new drawing.Pen(pen)。
3. 渐变坐标是绝对像素
createLinearGradient的起点和终点用的是画布上的绝对坐标,不是相对坐标。如果你画了一个矩形从 (100, 100) 到 (400, 300),渐变的起点终点也要在这个范围内才有意义。
小结
Brush 和 Pen 的进阶功能:
| 功能 | Brush | Pen | 说明 |
|---|---|---|---|
| 抗锯齿 | setAntiAlias | setAntiAlias | 让边缘更平滑 |
| 透明度 | setAlpha | setAlpha | 0-255 |
| 渐变色 | setShaderEffect | setShaderEffect | 线性/径向/扫描 |
| 阴影 | setShadowLayer | setShadowLayer | 仅文字生效 |
| 混合模式 | setBlendMode | - | 颜色叠加方式 |
| 颜色滤波 | setColorFilter | setColorFilter | 颜色变换 |
| 图像滤波 | setImageFilter | setImageFilter | 模糊等效果 |
| 路径效果 | - | setPathEffect | 虚线等 |
下一篇我们来看 Path(路径)——怎么画直线、曲线、贝塞尔曲线,做出各种复杂的形状。
