制作大风车动画

这个案例的风车旋转应用了图形变换来实现,速度和缩放比例应用slider来实现,其中图片的速度,图片大小的信息通过@State来定义变量管理,速度和和缩放比例的即时的值通过@Prop来管理。

1. 案例效果截图

2. 案例运用到的知识点

2.1. 核心知识点

  • Text组件:文本组件,用于呈现一段信息。
  • Image组件:图片组件,用来渲染展示图片。
  • Slider组件:滑动条组件,用来快速调节设置值,如音量、亮度等。

2.2. 其他知识点

  • ArkTS语言基础
  • 自定义组件和组件生命周期
  • V1状态管理:@State/@Prop
  • 内置组件:Column/Image/Text/Row/Stack/Blank/Button
  • 常量与资源分类的访问

3. 代码结构

├──entry/src/main/ets             // 代码区      
│  ├──common                        
│  │  └──Constants.ets            // 常量
│  ├──entryability
│  │  └──EntryAbility.ts          // 应用的入口
│  ├──pages
│  │  └──SliderPage.ets           // 入口页面
│  └──view                         
│     └──PanelComponent.ets       // 自定义组件
└──entry/src/main/resources       // 资源文件目录

4. 公共文件与资源

本案例涉及到的常量类和工具类代码如下:

4.1. 通用常量类

// entry/src/main/ets/common/Constant.ets
export enum RotatePosition {X = 0,Y = 0,Z = 1,
}export enum SliderSpeed {MIN = 1,MAX = 10,STEP = 1,
}export enum SliderMode {SPEED = 1,SCALE = 2,
}export class Constants {static readonly FONT_SIZE = 14static readonly LAYOUT_WEIGHT = 1static readonly PERCENTAGE_100 = '100%'static readonly DELAY_TIME = 15static readonly SLIDER_SKIN = $r('app.color.slider_color')static readonly INTERVAL = 0static readonly SPEED = 5static readonly WEIGHT_BLANK_IMAGE = '25%'static readonly PANEL_MARGIN_TOP = '4%'static readonly PANEL_MARGIN_BOTTOM = '5%'static readonly IMAGE_SIZE = 150static readonly ANGLE = 0static readonly IMAGE_SIZE_INITIAL = 1static readonly FRACTION_DIGITS = 1static readonly TITLE_PADDING = 5static readonly TITLE_MARGIN_HORIZONTAL = 10static readonly SPEED_MARGIN_BOTTOM = 6static readonly SLIDER_MARGIN_HORIZONTAL = 11static readonly PANEL_RADIUS = 24static readonly PANEL_IMAGE_WIDTH = 19static readonly PANEL_IMAGE_HEIGHT = 16static readonly PANEL_IMAGE_BIG_HEIGHT = 18static readonly PANEL_IMAGE_BIG_WIDTH = 22static readonly PANEL_WIDTH = '98%'static readonly PANEL_FONT_SIZE = 20static readonly PANEL_END_FONT_SIZE = 24static readonly PANEL_HOLDER = 'A'static readonly PANEL_HEIGHT = 100static readonly PANEL_PADDING = 10static readonly PANEL_MARGIN = 10static readonly MIN: number = 0.5static readonly MAX: number = 2.5static readonly STEP: number = 0.1
}

本案例涉及到的资源文件如下:

4.2. string.json

// entry/src/main/resources/base/element/string.json
{"string": [{"name": "module_desc","value": "module description"},{"name": "EntryAbility_desc","value": "description"},{"name": "EntryAbility_label","value": "label"},{"name": "scale_text","value": "缩放比例"},{"name": "speed_text","value": "速度"}]
}

4.3. color.json

// entry/src/main/resources/base/element/color.json
{"color": [{"name": "start_window_background","value": "#FFFFFF"},{"name": "white","value": "#FFFFFF"},{"name": "slider_color","value": "#007dff"},{"name": "background_color","value": "#F1F3F5"},{"name": "font_color","value": "#182431"}]
}

其他资源请到源码中获取。

5. 单个页面扁平实现

// entry/src/main/ets/pages/Index.ets
import { Constants, RotatePosition, SliderMode, SliderSpeed
} from '../common/Constants'@Entry
@Component
struct Index {@State private speed: number = Constants.SPEED@State private imageSize: number = Constants.IMAGE_SIZE_INITIAL@State private angle: number = Constants.ANGLEprivate interval: number = Constants.INTERVALbuild() {Column() {Image($rawfile('windmill.png')).objectFit(ImageFit.Contain).height(Constants.IMAGE_SIZE).width(Constants.IMAGE_SIZE).rotate({x: RotatePosition.X,y: RotatePosition.Y,z: RotatePosition.Z,angle: this.angle}).scale({ x: this.imageSize, y: this.imageSize }).margin({ bottom: Constants.WEIGHT_BLANK_IMAGE })Column() {Text($r('app.string.speed_text')).width(Constants.PANEL_WIDTH).padding({ left: Constants.TITLE_PADDING }).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({left: Constants.TITLE_MARGIN_HORIZONTAL,right: Constants.TITLE_MARGIN_HORIZONTAL})Column() {Text(this.speed.toFixed(Constants.FRACTION_DIGITS)).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })Row() {Image($rawfile('speedLow.png')).objectFit(ImageFit.Contain).height(Constants.PANEL_IMAGE_HEIGHT).width(Constants.PANEL_IMAGE_WIDTH)Slider({value: this.speed,min: SliderSpeed.MIN,max: SliderSpeed.MAX,step: SliderSpeed.STEP,style: SliderStyle.InSet}).layoutWeight(Constants.LAYOUT_WEIGHT).selectedColor(Constants.SLIDER_SKIN).onChange((value: number) => {this.speed = valueclearInterval(this.interval)this.speedChange()}).margin({left: Constants.SLIDER_MARGIN_HORIZONTAL,right: Constants.SLIDER_MARGIN_HORIZONTAL})Image($rawfile('speed.png')).objectFit(ImageFit.Contain).height(Constants.PANEL_IMAGE_BIG_HEIGHT).width(Constants.PANEL_IMAGE_BIG_WIDTH).height(Constants.PANEL_IMAGE_BIG_HEIGHT).width(Constants.PANEL_IMAGE_BIG_WIDTH)}}.justifyContent(FlexAlign.Center).backgroundColor(Color.White).borderRadius(Constants.PANEL_RADIUS).height(Constants.PANEL_HEIGHT).width(Constants.PANEL_WIDTH).padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).margin({top: Constants.PANEL_MARGIN,bottom: Constants.PANEL_MARGIN})}.padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).width(Constants.PERCENTAGE_100).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)Column() {Text($r('app.string.scale_text')).width(Constants.PANEL_WIDTH).padding({ left: Constants.TITLE_PADDING }).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({left: Constants.TITLE_MARGIN_HORIZONTAL,right: Constants.TITLE_MARGIN_HORIZONTAL})Column() {Text(this.imageSize.toFixed(Constants.FRACTION_DIGITS)).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })Row() {Text(Constants.PANEL_HOLDER).fontSize(Constants.PANEL_FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })Slider({value: this.imageSize,min: Constants.MIN,max: Constants.MAX,step: Constants.STEP,style: SliderStyle.InSet}).layoutWeight(Constants.LAYOUT_WEIGHT).selectedColor(Constants.SLIDER_SKIN).onChange((value: number) => {this.imageSize = value}).margin({left: Constants.SLIDER_MARGIN_HORIZONTAL,right: Constants.SLIDER_MARGIN_HORIZONTAL})Text(Constants.PANEL_HOLDER).fontSize(Constants.PANEL_END_FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })}}.justifyContent(FlexAlign.Center).backgroundColor(Color.White).borderRadius(Constants.PANEL_RADIUS).height(Constants.PANEL_HEIGHT).width(Constants.PANEL_WIDTH).padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).margin({top: Constants.PANEL_MARGIN,bottom: Constants.PANEL_MARGIN})}.padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).width(Constants.PERCENTAGE_100).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}.justifyContent(FlexAlign.End).height(Constants.PERCENTAGE_100).width(Constants.PERCENTAGE_100).backgroundColor($r('app.color.background_color'))}speedChange(): void {let that = thisthis.angle = Constants.ANGLEthis.interval = setInterval(() => {that.angle += that.speed}, Constants.DELAY_TIME)}onPageShow() {clearInterval(this.interval)this.speedChange()}
}

6. 组件抽离实现

6.1. 面板组件

// entry/src/main/ets/views/PanelComponent.ets
import { Constants, SliderMode } from '../common/Constants'@Component
export struct PanelComponent {@Prop text: string = ''title?: Resourcemode?: SliderModeoptions?: SliderOptionscallback: (value: number, mode: SliderChangeMode) => void = () => {}build() {Column() {Text(this.title).width(Constants.PANEL_WIDTH).padding({ left: Constants.TITLE_PADDING }).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({left: Constants.TITLE_MARGIN_HORIZONTAL,right: Constants.TITLE_MARGIN_HORIZONTAL})Column() {Text(this.text).fontSize(Constants.FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })Row() {if (this.mode === SliderMode.SPEED) {Image($rawfile('speedLow.png')).objectFit(ImageFit.Contain).height(Constants.PANEL_IMAGE_HEIGHT).width(Constants.PANEL_IMAGE_WIDTH)} else {Text(Constants.PANEL_HOLDER).fontSize(Constants.PANEL_FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })}Slider(this.options).layoutWeight(Constants.LAYOUT_WEIGHT).selectedColor(Constants.SLIDER_SKIN).onChange((value: number, mode: SliderChangeMode) => {this.callback(value, mode);}).margin({left: Constants.SLIDER_MARGIN_HORIZONTAL,right: Constants.SLIDER_MARGIN_HORIZONTAL})if (this.mode === SliderMode.SPEED) {Image($rawfile('speed.png')).objectFit(ImageFit.Contain).height(Constants.PANEL_IMAGE_BIG_HEIGHT).width(Constants.PANEL_IMAGE_BIG_WIDTH).height(Constants.PANEL_IMAGE_BIG_HEIGHT).width(Constants.PANEL_IMAGE_BIG_WIDTH)} else {Text(Constants.PANEL_HOLDER).fontSize(Constants.PANEL_END_FONT_SIZE).fontWeight(FontWeight.Medium).fontColor($r('app.color.font_color')).margin({ bottom: Constants.SPEED_MARGIN_BOTTOM })}}}.justifyContent(FlexAlign.Center).backgroundColor(Color.White).borderRadius(Constants.PANEL_RADIUS).height(Constants.PANEL_HEIGHT).width(Constants.PANEL_WIDTH).padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).margin({top: Constants.PANEL_MARGIN,bottom: Constants.PANEL_MARGIN})}.padding({left: Constants.PANEL_PADDING,right: Constants.PANEL_PADDING}).width(Constants.PERCENTAGE_100).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}
}

6.2. 页面改造

// entry/src/main/ets/pages/Index.ets
import { Constants, RotatePosition, SliderMode, SliderSpeed
} from '../common/Constants'
import { PanelComponent } from '../views/PanelComponent'@Entry
@Component
struct SliderPage {@State private speed: number = Constants.SPEED@State private imageSize: number = Constants.IMAGE_SIZE_INITIAL@State private angle: number = Constants.ANGLEprivate interval: number = Constants.INTERVALbuild() {Column() {Image($rawfile('windmill.png')).objectFit(ImageFit.Contain).height(Constants.IMAGE_SIZE).width(Constants.IMAGE_SIZE).rotate({x: RotatePosition.X,y: RotatePosition.Y,z: RotatePosition.Z,angle: this.angle}).scale({ x: this.imageSize, y: this.imageSize }).margin({ bottom: Constants.WEIGHT_BLANK_IMAGE })PanelComponent({mode: SliderMode.SPEED,title: $r('app.string.speed_text'),text: this.speed.toFixed(Constants.FRACTION_DIGITS),callback: ((value: number) => {this.speed = valueclearInterval(this.interval)this.speedChange()}),options: {value: this.speed,min: SliderSpeed.MIN,max: SliderSpeed.MAX,step: SliderSpeed.STEP,style: SliderStyle.InSet}})PanelComponent({mode: SliderMode.SCALE,title: $r('app.string.scale_text'),text: this.imageSize.toFixed(Constants.FRACTION_DIGITS),callback: ((value: number) => {this.imageSize = value}),options: {value: this.imageSize,min: Constants.MIN,max: Constants.MAX,step: Constants.STEP,style: SliderStyle.InSet}}).margin({bottom: Constants.PANEL_MARGIN_BOTTOM,top: Constants.PANEL_MARGIN_TOP})}.justifyContent(FlexAlign.End).height(Constants.PERCENTAGE_100).backgroundColor($r('app.color.background_color'))}speedChange(): void {let that = thisthis.angle = Constants.ANGLEthis.interval = setInterval(() => {that.angle += that.speed}, Constants.DELAY_TIME)}onPageShow() {clearInterval(this.interval)this.speedChange()}
}

7. 代码与视频教程

完整案例代码与视频教程请参见:

代码:Code-05-02.zip。

视频:《大风车吱扭扭的转》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83468.shtml

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

相关文章

代码随想录算法训练营第四十二四十三天

LeetCode/卡码网题目: 42. 接雨水84. 柱状图中最大的矩形98. 所有可达路径 其他: 今日总结 往期打卡 42. 接雨水 跳转: 42. 接雨水 学习: 代码随想录公开讲解 问题: 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能…

SEO 优化实战:ZKmall模板商城的 B2C商城的 URL 重构与结构化数据

在搜索引擎算法日益复杂的今天,B2C商城想要在海量信息中脱颖而出,仅靠优质商品和营销活动远远不够。ZKmall模板商城以实战为导向,通过URL 重构与结构化数据优化两大核心策略,帮助 B2C 商城实现从底层架构到搜索展示的全面升级&…

Linux自有服务

自有服务概述 概述 自有服务,即不需要用户独立去安装的软件的服务,而是当系统安装好之后就可以直接使用的服务(内置) 显示服务 显示服务 命令:systemctl \[选项] 选项参数 list-units --type service --all&#x…

ZYNQ Overlay硬件库使用指南:用Python玩转FPGA加速

在传统的FPGA开发中,硬件设计需要掌握Verilog/VHDL等硬件描述语言,这对软件开发者而言门槛较高。Xilinx的PYNQ框架通过Overlay硬件库彻底改变了这一现状——开发者只需调用Python API即可控制FPGA的硬件模块,实现硬件加速与灵活配置。本文将深入探讨ZYNQ Overlay的核心概念、…

JavaScript入门【1】概述

1.JavaScript是什么? <font style"color:rgb(38,38,38);">Javascript &#xff08;简称“JS”&#xff09;是⼀种直译式脚本语⾔&#xff0c;⼀段脚本其实就是⼀系列指令&#xff0c;计算机通过这些指令来达成⽬标。它⼜是⼀种动态类型的编程语⾔。JS⽤来在⽹…

c++从入门到精通(五)--异常处理,命名空间,多继承与虚继承

异常处理 栈展开过程&#xff1a; 栈展开过程沿着嵌套函数的调用链不断查找&#xff0c;直到找到了与异常匹配的catch子句为止&#xff1b;也可能一直没找到匹配的catch&#xff0c;则退出主函数后查找过程终止。栈展开过程中的对象被自动销毁。 在栈展开的过程中&#xff0c…

自适应稀疏核卷积网络:一种高效灵活的图像处理方案

自适应稀疏核卷积网络&#xff1a;一种高效灵活的图像处理方案 引言 在深度学习的大潮中&#xff0c;计算机视觉技术取得了长足的进步。其中&#xff0c;卷积神经网络&#xff08;CNN&#xff09;作为图像处理的核心工具&#xff0c;极大地推动了各类图像识别任务的效果提升。…

Nginx:利用 FreeSSL 申请(Https)免费证书的技术指南

1、简述 在现代互联网应用中,使用 HTTPS 连接是确保数据传输安全的基本需求。SSL/TLS 证书能够加密客户端与服务器之间的通信,防止中间人攻击等安全隐患。而许多开发者和小型企业可能会担心 SSL 证书的费用问题。幸运的是,FreeSSL 提供了一个简单易用的平台,允许我们申请免…

自定义库模块增加自定义许可操作详细方法

自定义库模块增加自定义许可操作详细方法 用到的工具: 后面程序用到的所有代码均是该工具生成的秘密&#xff01;&#xff01;&#xff01;&#xff01; 【切记切记&#xff01;&#xff01;&#xff01; 一定要记住密码&#xff0c;不然如果你想将库的许可认证移除&#xf…

python的漫画网站管理系统

目录 技术栈介绍具体实现截图![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0ed2084038144499a162b3fb731a5f37.png)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a76a091066f74a80bf7ac1be489ae8a8.png)系统设计研究方法&#xff1a;设计步骤设计流程核…

Python循环性脚本实践要点:打造稳定高效的定时任务

在Python开发中&#xff0c;循环性脚本&#xff08;长时间运行并定期执行任务的脚本&#xff09;非常常见&#xff0c;比如监控系统、数据采集程序、定时清理任务等。这类脚本虽然看似简单&#xff0c;但实际开发中容易遇到各种陷阱。本文将分享六大核心实践要点&#xff0c;帮…

编程基础:什么是变量

文章目录 变量&#xff1a;双要素变量必须代表一个意义&#xff1a;编程不需要无意义的变量。只要是变量&#xff0c;都需要有一个意义。变量必须要有不同的值&#xff1a;编程不需要只有一个值的变量。只要是变量&#xff0c;都需要有不同的值。 双要素少一个都不是变量即看见…

利用SenseGlove触觉手套开发XR手术训练体验

VirtualiSurg和VR触觉 作为领先的培训平台&#xff0c;VirtualiSurg自2017年以来一直利用扩展现实 (XR) 和触觉技术&#xff0c;为全球医疗保健行业提供个性化、数据驱动的学习解决方案。该平台赋能医疗专业人员进行协作式学习和培训&#xff0c;提升他们的技能&#xff0c;使…

【记录】Windows|竖屏怎么调整分辨率使横竖双屏互动鼠标丝滑

本文版本&#xff1a;Windows11&#xff0c;记录一下&#xff0c;我最后调整的比较舒适的分辨率是800*1280。 文章目录 第一步 回到桌面第二步 右键桌面第三步 设置横屏为主显示器第四步 调整分辨率使之符合你的需求第五步 勾选轻松在显示器之间移动光标第六步 拖动屏幕符合物理…

手机打电话时如何将通话对方的声音在手机上识别成文字

手机打电话时如何将通话对方的声音在手机上识别成文字 --本地AI电话机器人 上一篇&#xff1a;手机打电话时由对方DTMF响应切换多级IVR语音应答&#xff08;一&#xff09; 下一篇&#xff1a;手机打电话时由对方DTMF响应切换多级IVR语音应答&#xff08;二&#xff09; 一、…

uniapp-商城-61-后台 新增商品(添加商品到数据库)

完成商品的布局&#xff0c;完成商品的属性添加&#xff0c;最后的目的还是要完成数据添加&#xff0c;将我们前台的数据添加后台的数据库。 1、界面 2、点击提交完成商品添加 点击下方的提交按钮&#xff0c;将数据添加到数据库。 onSubmit 使用该函数---见3 <view cla…

A级、B级弱电机房数据中心建设运营汇报方案

该方案围绕A 级、B 级弱电机房数据中心建设与运营展开,依据《数据中心设计规范》等标准,施工范围涵盖 10 类机房及配套设施,采用专业化施工团队与物资调配体系,强调标签规范、线缆隐藏等细节管理。运营阶段建立三方协同运维模式,针对三级故障制定30 分钟至 1 小时响应机制…

RAG数据处理:PDF/HTML

RAG而言用户输入的数据通常是各种各样文档&#xff0c;本文主要采用langchain实现PDF/HTML文档的处理方法 PDF文档解析 PDF文档很常见格式&#xff0c;但内部结构常常较复杂&#xff1a; 复杂的版式布局多样的元素&#xff08;段落、表格、公式、图片等&#xff09;文本流无…

时源芯微| KY键盘接口静电浪涌防护方案

KY键盘接口静电浪涌防护方案通过集成ESD保护元件、电阻和连接键&#xff0c;形成了一道有效的防护屏障。当键盘接口受到静电放电或其他浪涌冲击时&#xff0c;该方案能够迅速将过电压和过电流引导至地&#xff0c;从而保护后续电路免受损害。 ESD保护元件是方案中的核心部分&a…

Java 原生网络编程(BIO | NIO | Reactor 模式)

1、基本常识 Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层&#xff0c;是一组接口&#xff0c;使用了门面模式对应用层隐藏了传输层以下的实现细节。TCP 用主机的 IP 地址加上主机端口号作为 TCP 连接的端点&#xff0c;该端点叫做套接字 Socket。 比如三次握手&…