「Mac畅玩鸿蒙与硬件22」鸿蒙UI组件篇12 - Canvas 组件的动态进阶应用

devtools/2024/11/6 21:59:15/

在鸿蒙应用中,Canvas 组件可以实现丰富的动态效果,适合用于动画和实时更新的场景。本篇将介绍如何在 Canvas 中实现动画循环、动态进度条、旋转和缩放动画,以及性能优化策略。

在这里插入图片描述


关键词
  • Canvas 组件
  • 动态绘制
  • 动画效果
  • 动态进度条
  • 旋转和缩放
  • 性能优化

一、使用定时器实现动画循环

通过定时更新画布内容,可以让图形在 Canvas 中产生动画效果。setTimeout 方法可用于实现帧刷新,使图形流畅移动。

1.1 动画循环示例:水平移动

以下代码展示了如何在 Canvas 上创建一个自动移动的圆形。

@Entry
@Component
struct MovingCircleExample {private x: uiltin">number = 0; // 圆心的 x 坐标private dx: uiltin">number = 5; // 每帧的水平移动距离private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(); // 创建 Canvas 渲染上下文build() {Column() {Canvas(this.context).width('100%').height(600).onReady(() => {this.animateCircle(); // 开始动画});}}private animateCircle(): void {this.context.clearRect(0, 0, 600, 600); // 清除画布this.context.beginPath(); // 开始新路径this.context.arc(this.x, 300, 50, 0, 2 * Math.PI); // 绘制圆形this.context.fillStyle = '#FF4500'; // 设置填充颜色为橙色this.context.fill(); // 填充圆形this.x += this.dx; // 更新圆心的 x 坐标if (this.x > 600 || this.x < 0) {this.dx = -this.dx; // 碰到边界时反向}// 使用 setTimeout 模拟帧刷新setTimeout(() => this.animateCircle(), 16); // 约60帧每秒}
}

效果示例:一个橙色圆形在 Canvas 中水平往返移动,碰到边界会反弹。
在这里插入图片描述


二、动态进度条

动态进度条是 Canvas 的常见应用。以下示例展示了如何使用 CanvassetInterval 创建一个动态的进度条,进度条会在画布中自动增加。

@Entry
@Component
struct AnimatedProgressBarExample {private progress: uiltin">number = 0; // 进度条当前进度private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(); // 创建 Canvas 渲染上下文build() {Column() {Canvas(this.context).width('100%').height(300).onReady(() => {this.startProgress(); // 开始进度条});}}// 动态绘制进度条的方法startProgress() {setInterval(() => {this.context.clearRect(0, 0, 600, 300); // 清除画布// 绘制进度条背景this.context.fillStyle = '#D3D3D3'; // 设置背景颜色为浅灰色this.context.fillRect(50, 100, 500, 50); // 绘制进度条背景// 绘制进度条this.context.fillStyle = '#32CD32'; // 设置进度条颜色为绿色this.context.fillRect(50, 100, (500 * this.progress) / 100, 50); // 绘制当前进度// 显示进度百分比文本this.context.font = '24px sans-serif'; // 设置字体样式this.context.fillStyle = '#000000'; // 设置文本颜色为黑色this.context.fillText(`${this.progress}%`, 280, 135); // 绘制进度文本this.progress = (this.progress + 1) % 101; // 更新进度}, 50); // 每50毫秒更新一次}
}

效果示例:一个绿色的进度条在 Canvas 上动态增加,并显示当前百分比。

在这里插入图片描述


三、复杂动画示例:旋转和缩放

结合 rotatescale 方法,可以在 Canvas 中实现图形的旋转和缩放动画。

@Entry
@Component
struct RotateAndScaleAnimation {private scale1: uiltin">number = 1; // 当前缩放比例private rotation: uiltin">number = 0; // 当前旋转角度private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(); // 创建 Canvas 渲染上下文build() {Column() {Canvas(this.context).width('100%').height(600).onReady(() => {this.animateShape(); // 开始动画});}}private animateShape(): void {this.context.clearRect(0, 0, 600, 600); // 清除画布this.context.save(); // 保存当前绘图状态// 平移到中心点this.context.translate(300, 300); // 将原点移动到 (300, 300)this.context.rotate(this.rotation); // 应用旋转this.context.scale(this.scale1, this.scale1); // 应用缩放// 绘制图形this.context.fillStyle = '#4682B4'; // 设置填充颜色为蓝色this.context.fillRect(-50, -50, 100, 100); // 绘制中心点为 (300, 300) 的方块this.context.restore(); // 恢复到之前的状态// 更新旋转角度和缩放比例this.rotation += 0.1; // 每帧增加旋转角度this.scale1 = this.scale1 >= 1.5 ? 1 : this.scale1 + 0.01; // 循环缩放// 使用 setTimeout 模拟帧刷新setTimeout(() => this.animateShape(), 16); // 约60帧每秒}
}

效果示例:一个蓝色的方块在画布上旋转并缩放,循环往复。

在这里插入图片描述


四、性能优化策略

当应用复杂图形或大量动画时,优化 Canvas 性能变得至关重要。以下是几种常用的性能优化策略。

4.1 减少不必要的重绘

在动态绘制中,避免重复重绘不需要更新的区域。使用 clearRect 精确清除指定区域,减少全局重绘的开销。

@Entry
@Component
struct OptimizedDrawingExample {private x: uiltin">number = 0; // 圆心的 x 坐标private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(); // 创建 Canvas 渲染上下文build() {Canvas(this.context).width('100%').height(500).onReady(() => {this.animate(); // 开始动画});}private animate = () => {// 清除上一帧的圆形this.context.clearRect(this.x - 2, 150, 52, 52); // 精确清除指定区域this.x += 2; // 更新 x 坐标this.context.beginPath(); // 开始新路径this.context.arc(this.x, 200, 25, 0, 2 * Math.PI); // 绘制圆形this.context.fillStyle = '#32CD32'; // 设置填充颜色为绿色this.context.fill(); // 填充圆形if (this.x > 500) this.x = 0; // 碰到边界时重置位置setTimeout(this.animate, 16); // 约60帧每秒}
}

效果示例:圆形在水平移动时仅清除上一位置的小范围区域,从而优化重绘性能。

在这里插入图片描述


4.2 使用离屏 Canvas

使用离屏 Canvas 可以在不影响主线程的情况下进行复杂的图形运算,绘制完成后再一次性渲染到主 Canvas 上。

@Entry
@Component
struct OffscreenCanvasExample {private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(500, 500); // 定义离屏 Canvasprivate offscreenContext!: OffscreenCanvasRenderingContext2D; // 声明离屏 Canvas 渲染上下文private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(); // 创建主 Canvas渲染上下文build() {Canvas(this.context).width('100%').height(500).onReady(() => {this.offscreenContext = this.offscreenCanvas.getContext('2d')!; // 获取离屏 Canvas 渲染上下文this.drawOffscreen(); // 绘制离屏 Canvasconst imageBitmap = this.offscreenCanvas.transferToImageBitmap(); // 转换为 ImageBitmapthis.context.drawImage(imageBitmap, 0, 0); // 将离屏 Canvas 绘制到主 Canvas});}private drawOffscreen() {this.offscreenContext.fillStyle = '#8A2BE2'; // 设置填充颜色为紫色this.offscreenContext.fillRect(50, 50, 400, 400); // 在离屏 Canvas 上绘制矩形this.offscreenContext.beginPath(); // 开始新路径this.offscreenContext.arc(250, 250, 100, 0, 2 * Math.PI); // 绘制圆形this.offscreenContext.fillStyle = '#FFD700'; // 设置填充颜色为金色this.offscreenContext.fill(); // 填充圆形}
}

效果示例:复杂图形先在离屏 Canvas 中完成,再一次性绘制到主 Canvas 上,提升了渲染性能。

在这里插入图片描述


小结

本篇介绍了鸿蒙 Canvas 组件的动态进阶应用,包括动画循环、动态进度条、旋转和缩放动画,以及性能优化策略。通过这些技术,开发者可以实现流畅的动态效果,为应用带来更生动的视觉体验。


下一篇预告

在下一篇中,我们将探索鸿蒙的自定义组件功能,学习如何创建可复用的自定义组件来提升代码的灵活性和复用性。


上一篇:「Mac畅玩鸿蒙与硬件21」鸿蒙UI组件篇11 - Canvas 组件的静态进阶应用
下一篇:「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用


http://www.ppmy.cn/devtools/131848.html

相关文章

信息学科平台系统开发:Spring Boot实用指南

3系统分析 3.1可行性分析 通过对本基于保密信息学科平台系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于保密信息学科平台系统采用Spring Boot框架&a…

数据库基础(6) . DDL

3.2.DDL 数据定义语言 DDL : Data Definition Language 用于创建新的数据库、模式&#xff08;schema&#xff09;、表&#xff08;tables&#xff09;、视图&#xff08;views&#xff09;以及索引&#xff08;indexes&#xff09;等。 常见的DDL语句包括SHOW、CREATE、DRO…

Spring Boot驱动的导师双选系统:设计与实现

第一章 绪论 1.1 选题背景 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;尽管身边每时每刻都在产生大量信息&#xff0c;这些信息也都会在短时间内得到处理&#xff0c;并迅速传播。因为很多时候&#xff0c;管理层决策需要大量信…

聚合 SDK 广告的工作原理及优势

聚合 SDK 广告的工作原理通常包括以下几个主要步骤&#xff1a; 1. 集成聚合 SDK&#xff1a;开发者将聚合 SDK 集成到其应用程序中。 2. 配置参数&#xff1a;开发者在聚合 SDK 中设置各种参数&#xff0c;例如广告平台的优先级、广告类型偏好、出价策略等。 3. 应用启动与请…

Python实例:爱心代码

前言 在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。 爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,…

算子级血缘助企业数据管理“自动化、精细化、智能化”

经过这么多年的数字化转型&#xff0c;数据已成为驱动企业决策优化和运营效能提升的核心要素。在这个过程中&#xff0c;数据的发掘和利用&#xff0c;已经成为企业实现精细化运营、智能化决策的重要环节。因此&#xff0c;构建一个更高效、全面、精准的数据管理体系&#xff0…

sqlalchemy连接mysql数据库

create_engine() 是 SQLAlchemy 中用于创建数据库连接的函数&#xff0c;它接受多个参数来配置连接池、日志输出等方面。你提到的 create_engine(DATABASE_URI, echoTrue, pool_size5, max_overflow2, pool_timeout30) 中的各个参数的含义如下&#xff1a; 1. DATABASE_URI 意…

L1G3000 提示工程(Prompt Engineering)

什么是Prompt(提示词)? Prompt是一种灵活、多样化的输入方式&#xff0c;可以用于指导大语言模型生成各种类型的内容。什么是提示工程? 提示工程是一种通过设计和调整输入(Prompts)来改善模型性能或控制其输出结果的技术。 六大基本原则: 指令要清晰提供参考内容复杂的任务拆…