前言品牌闪屏是用户打开应用后看到的第一画面其视觉品质直接影响用户对应用的第一印象。“海风日记“的闪屏页通过 Canvas 2D API 绘制了多层波浪动画配合暖金渐变背景营造出“海风拂面“的品牌氛围。本文将从SplashPage.ets源码出发深入讲解 Canvas 2D 绘图的完整流程包括渲染上下文获取、贝塞尔曲线绘制波浪、多层叠加实现立体感以及动画循环的实现。一、Canvas 组件概述1.1 Canvas 的基本用法Canvas 是 ArkUI 提供的画布组件支持 2D 绘图 APIEntry Component struct SplashPage { private settings: RenderingContextSettings new RenderingContextSettings(true) private ctx: CanvasRenderingContext2D new CanvasRenderingContext2D(this.settings) build() { Canvas(this.ctx) .width(100%) .height(300) .onReady(() { this.drawWaves() }) } }1.2 Canvas 的关键要素要素类型说明RenderingContextSettings配置类控制 Canvas 渲染设置如是否抗锯齿CanvasRenderingContext2D渲染上下文提供 2D 绘图 APICanvas组件容器组件渲染画布显示绘图内容onReady回调生命周期Canvas 就绪后触发开始绘图1.3 Canvas 与 Shape 的对比对比维度CanvasShape绘图方式命令式 JS API声明式 XML 描述适用场景动态绘图、动画静态矢量图形性能适合复杂绘图适合简单图形动画需要 requestAnimationFrame配合 animateTo代码量较多较少二、Canvas 渲染上下文的创建2.1 RenderingContextSettingsprivate settings: RenderingContextSettings new RenderingContextSettings(true)RenderingContextSettings构造函数的参数参数类型说明antialiasboolean是否开启抗锯齿true为开启2.2 CanvasRenderingContext2Dprivate ctx: CanvasRenderingContext2D new CanvasRenderingContext2D(this.settings)CanvasRenderingContext2D是绘图的核心对象提供了以下 API 类别API 类别方法说明路径beginPath,moveTo,lineTo,bezierCurveTo绘制路径样式fillStyle,strokeStyle设置填充和描边样式填充fill,stroke填充和描边清除clearRect清除画布区域文字fillText,strokeText绘制文字图片drawImage绘制图片2.3 Canvas 的尺寸管理State canvasW: number 390 State canvasH: number 300 Canvas(this.ctx) .width(100%) .height(300) .onReady(() { this.canvasW 390 this.canvasH 300 this.drawWaves() })三、多层波浪绘制3.1 波浪层 1底层最浅drawWaves() { const w this.canvasW const h this.canvasH this.ctx.clearRect(0, 0, w, h) // 波浪层 1底层最浅 this.ctx.beginPath() this.ctx.moveTo(0, h * 0.55) this.ctx.bezierCurveTo(w * 0.2, h * 0.40, w * 0.4, h * 0.70, w * 0.6, h * 0.50) this.ctx.bezierCurveTo(w * 0.8, h * 0.30, w * 0.9, h * 0.60, w, h * 0.48) this.ctx.lineTo(w, h) this.ctx.lineTo(0, h) this.ctx.closePath() this.ctx.fillStyle rgba(255,210,140,0.35) this.ctx.fill() }3.2 波浪层 2中层// 波浪层 2中层 this.ctx.beginPath() this.ctx.moveTo(0, h * 0.65) this.ctx.bezierCurveTo(w * 0.25, h * 0.50, w * 0.45, h * 0.80, w * 0.65, h * 0.62) this.ctx.bezierCurveTo(w * 0.85, h * 0.45, w * 0.92, h * 0.72, w, h * 0.60) this.ctx.lineTo(w, h) this.ctx.lineTo(0, h) this.ctx.closePath() this.ctx.fillStyle rgba(245,166,35,0.25) this.ctx.fill()3.3 波浪层 3前景最深// 波浪层 3前景最深 this.ctx.beginPath() this.ctx.moveTo(0, h * 0.75) this.ctx.bezierCurveTo(w * 0.15, h * 0.62, w * 0.35, h * 0.88, w * 0.55, h * 0.72) this.ctx.bezierCurveTo(w * 0.75, h * 0.58, w * 0.88, h * 0.80, w, h * 0.70) this.ctx.lineTo(w, h) this.ctx.lineTo(0, h) this.ctx.closePath() this.ctx.fillStyle rgba(200,149,106,0.30) this.ctx.fill()3.4 三层波浪的参数对比参数波浪层 1波浪层 2波浪层 3起始 Y 位置h * 0.55h * 0.65h * 0.75控制点 1(w*0.2, h*0.40)(w*0.25, h*0.50)(w*0.15, h*0.62)控制点 2(w*0.4, h*0.70)(w*0.45, h*0.80)(w*0.35, h*0.88)控制点 3(w*0.6, h*0.50)(w*0.65, h*0.62)(w*0.55, h*0.72)控制点 4(w*0.8, h*0.30)(w*0.85, h*0.45)(w*0.75, h*0.58)填充颜色rgba(255,210,140,0.35)rgba(245,166,35,0.25)rgba(200,149,106,0.30)四、贝塞尔曲线绘制详解4.1 三次贝塞尔曲线bezierCurveTo绘制的是三次贝塞尔曲线需要两个控制点和一个终点ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)参数说明cp1x, cp1y第一个控制点坐标cp2x, cp2y第二个控制点坐标x, y终点坐标4.2 波浪曲线的控制点分析曲线段 1: (0, 0.55h) → (0.2w, 0.40h) → (0.4w, 0.70h) → (0.6w, 0.50h) ↑ 控制点 1 ↑ 控制点 2 ↑ 终点 曲线段 2: (0.6w, 0.50h) → (0.8w, 0.30h) → (0.9w, 0.60h) → (w, 0.48h) ↑ 控制点 1 ↑ 控制点 2 ↑ 终点4.3 波浪的视觉原理通过调整贝塞尔曲线的控制点位置可以改变波浪的形态控制点调整效果控制点 Y 值降低波浪向上凸起控制点 Y 值升高波浪向下凹陷控制点 X 值靠近波浪更陡峭控制点 X 值远离波浪更平缓五、Canvas 的事件处理5.1 onReady 事件Canvas(this.ctx) .onReady(() { this.canvasW 390 this.canvasH 300 this.drawWaves() })onReady在 Canvas 组件初始化完成后触发此时可以安全地进行绘图操作。5.2 Canvas 的其他事件事件说明onReadyCanvas 就绪可以开始绘图onAreaChangeCanvas 尺寸变化时触发onClick点击事件onTouch触摸事件5.3 Canvas 尺寸自适应Canvas(this.ctx) .width(100%) .height(300) .onAreaChange((oldWidth, oldHeight, newWidth, newHeight) { this.canvasW newWidth this.canvasH newHeight this.drawWaves() // 重新绘制 })六、Canvas 绘图的最佳实践6.1 性能优化避免频繁 clearRect只在需要更新时清除画布减少路径复杂度过多的控制点会影响性能使用离屏 Canvas复杂图形可以先绘制到离屏 Canvas 再复制6.2 绘制顺序Canvas 的绘制顺序遵循后绘制的在上层的原则1. clearRect() ← 清除画布 2. 波浪层 1 绘制 ← 最底层最先绘制 3. 波浪层 2 绘制 ← 中间层 4. 波浪层 3 绘制 ← 最上层最后绘制6.3 颜色叠加效果通过半透明颜色的叠加可以产生丰富的视觉效果// 三层半透明颜色叠加 rgba(255,210,140,0.35) // 底层浅橙色透明度 35% rgba(245,166,35,0.25) // 中层品牌橙透明度 25% rgba(200,149,106,0.30) // 顶层琥珀色透明度 30%七、常见问题与排查7.1 Canvas 显示空白问题Canvas 区域显示为空白。原因未在onReady中调用绘图方法或绘图坐标超出 Canvas 范围。解决方案Canvas(this.ctx) .onReady(() { this.draw() // 必须在 onReady 中调用 })7.2 绘图不清晰问题Canvas 绘制的图形有锯齿。解决方案确保RenderingContextSettings的antialias参数为trueprivate settings: RenderingContextSettings new RenderingContextSettings(true)7.3 Canvas 尺寸为 0问题无法获取 Canvas 的正确尺寸。原因在onReady之前读取 Canvas 尺寸。解决方案在onReady回调中获取尺寸。总结本文通过“海风日记“闪屏页的源码深入讲解了 Canvas 2D 绘图的完整流程Canvas 组件渲染上下文创建、基本配置多层波浪三层贝塞尔曲线波浪的绘制方法贝塞尔曲线bezierCurveTo的控制点原理事件处理onReady、onAreaChange等事件最佳实践性能优化、绘制顺序、颜色叠加下一篇文章将深入讲解LinearGradient 线性渐变在品牌色中的应用敬请期待。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源Canvas 组件文档CanvasRenderingContext2D API贝塞尔曲线绘制指南海风日记项目源码[HarmonyOS 开发者官网](https://atomgit.com/openharmony/docs开源鸿蒙跨平台社区ArkUI 动画概述Canvas 性能优化