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

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

在这里插入图片描述


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

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

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

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

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

@Entry
@Component
struct MovingCircleExample {private x: number = 0; // 圆心的 x 坐标private dx: 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: 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: number = 1; // 当前缩放比例private rotation: 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: 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.rhkb.cn/news/466082.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python练习10

Python日常练习 题目&#xff1a; 编写程序&#xff0c;输出如下所示图案。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 要求&#xff1a; 使用for循环的方式完成 --------------------------------------------------------- 注意&#xff1a; …

【前端】html的8个常用标签

HTML html 超文本链接(标记)语言 H5 HTML v5 get/post/delete/put —— restful 网络规划 Web开发 结构样式动作 架构 装饰 交互&#xff08;动作&#xff09; 装饰做好了–> UI工程师 标签 文本相关 图片、图像、声音 导航 表格* 列表 表单标签* 布局标签 H5…

Java高效学习家教平台系统小程序源码

&#x1f4da; 家教平台系统&#xff1a;让孩子学习更高效的秘密武器 &#x1f680; &#x1f469;‍&#x1f3eb; 引言&#xff1a;家教新风尚&#xff0c;线上平台引领教育潮流 在这个信息爆炸的时代&#xff0c;家教平台系统如同雨后春笋般涌现&#xff0c;为孩子们的学习…

Qt多边形填充/不填充绘制

1 填充多边形绘制形式 void GraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {Q_UNUSED(option);Q_UNUSED(widget);//painter->setPen(pen()); // 设置默认画笔//painter->setBrush(brush()); // 设置默…

OpenAI大事记;GPT到ChatGPT参数量进化

目录 OpenAI大事记 GPT到ChatGPT参数量进化 OpenAI大事记 GPT到ChatGPT参数量进化 ChatGPT是从初代 GPT逐渐演变而来的。在进化的过程中,GPT系列模型的参数数量呈指数级增长,从初代GPT的1.17亿个参数,到GPT-2的15 亿个参数,再到 GPT-3的1750 亿个参数。模型越来越大,训练…

一文了解Java序列化

Java 序列化&#xff08;Serialization&#xff09;是将对象的状态转换为字节流&#xff0c;以便将对象的状态保存到文件中或通过网络传输的过程。反序列化&#xff08;Deserialization&#xff09;则是将字节流恢复为原始对象。Java 序列化主要通过 Serializable 接口实现。 为…

vue解决跨域问题

1、在vue项目的根目录创建vue.config.js的文件 复制以下带代码 devServer: {proxy: {/api: {target: http://localhost:3000, // 目标服务器地址changeOrigin: true, // 是否改变源pathRewrite: {^/api: // 重写路径&#xff0c;例如将/api/user重写为/user}}}}2、将接口的地…

是时候用开源降低AI落地门槛了

过去三十多年&#xff0c;从Linux到KVM&#xff0c;从OpenStack到Kubernetes&#xff0c;IT领域众多关键技术都来自开源。开源技术不仅大幅降低了IT成本&#xff0c;也降低了企业技术创新的门槛。 那么&#xff0c;在生成式AI时代&#xff0c;开源能够为AI带来什么&#xff1f;…

基于SSM+VUE守护萌宠宠物网站JAVA|VUE|Springboot计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

Oh My Posh安装

nullSet up your terminalhttps://ohmyposh.dev/docs/installation/windows Git ee oh-my-posh: Windows上的oh-my-zsh&#xff0c;源地址 https://github.com/JanDeDobbeleer/oh-my-posh.git (gitee.com)https://gitee.com/efluent/oh-my-posh

基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)

&#x1f388;系统亮点&#xff1a;协同过滤算法、节流算法、支付宝沙盒支付、图形化分析、实时聊天&#xff1b; 一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk1…

Webserver(4.8)UDP、广播、组播

目录 UDP通信server.cclient.c 广播client.cserver.c 组播client.cserver.c UDP通信 server.c #include<arpa/inet.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> int main(){//1.创建一个通信的socketint f…

大数据集群中实用的三个脚本文件解析与应用

目录 一、jps - cluster.sh 脚本文件 &#xff08;一&#xff09;背景与功能 &#xff08;二&#xff09;使用方法 二、集群文件分发脚本 xsync.sh &#xff08;一&#xff09;背景与问题 &#xff08;二&#xff09;功能与实现原理 &#xff08;三&#xff09;脚本编写…

普通人没钱又没能力的话,那就踏实学一门手艺

其实想在这个社会上谋生有很多种方式&#xff0c;大致可以分为这么几个类型。 ​ 1&#xff1a;劳动型 大多数人无疑都是从事的劳动型工作&#xff0c;靠出卖体力挣钱&#xff0c;如建筑工人、快递员、服务员&#xff0c;车间杂工等等。这种性质的工作比较累&#xff0c;性价…

数据管理的四大支柱:揭秘数据中台、数据仓库、数据治理和主数据

文章目录 一、数据中台&#xff1a;数据的“中央厨房”二、数据仓库&#xff1a;数据的“图书馆”三、数据治理&#xff1a;数据的“交警”四、主数据&#xff1a;数据的“身份证”五、定位与差异&#xff1a;协同作战的团队成员 在数字化时代&#xff0c;企业数据管理变得至关…

RabbitMQ 的集群

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ 的集群】面试题&#xff1f;希望对大家有帮助&#xff1b; RabbitMQ 的集群 RabbitMQ 是一种流行的开源消息代理&#xff0c;广泛用于构建分布式系统中的消息队列。随着应用程序规模的扩大&#xff0c;单一的 RabbitMQ 实…

PostgreSQL核心揭秘(三)-元组结构

目录 概述 2. 堆元组介绍 1&#xff09;HeapTupleHeaderData 结构 2&#xff09;空值位图&#xff08;Null Bitmap&#xff09; 3&#xff09;用户数据&#xff08;User Data&#xff09; 3. 元组增、删、改操作介绍 1&#xff09;增&#xff08;INSER…

在数据抓取的时候,短效IP比长效IP有哪些优势?

在数据抓取领域&#xff0c;代理IP的选择对于任务的成功率和效率至关重要。短效IP和长效IP各有其特点和适用场景&#xff0c;但在数据抓取过程中&#xff0c;短效IP因其独特的优势而受到青睐。本文将和大家一起探讨短效IP在数据抓取中相比长效IP的优势。 短效IP的定义与特点 …

Navicat for MySQL 错误:1251

mySql&#xff1a;8.4 Navicat for MySQL&#xff1a;11.0.10 企业版 绿色版 官网中关于mysql_native_password插件的说法&#xff1a;链接 1. 问题 连接数据库报错&#xff1a;1251 要求升级Navicat for MySQL 2. 原因 mysql中的mysql_native_password插件默认是关闭的 …

RabbitMQ 管理平台(控制中心)的介绍

文章目录 一、RabbitMQ 管理平台整体介绍二、Overview 总览三、Connections 连接四、Channels 通道五、Exchanges 交换机六、Queues 队列查看队列详细信息查看队列的消息内容 七、Admin 用户给用户分配虚拟主机 一、RabbitMQ 管理平台整体介绍 RabbitMQ 管理平台内有六个模块&…