鸿蒙开发案例:指南针

【1】引言(完整代码在最后面)

在本文中,我们将介绍如何使用鸿蒙系统(HarmonyOS)开发一个简单的指南针应用。通过这个案例,你可以学习如何使用传感器服务、状态管理以及UI构建等基本技能。

【2】环境准备

电脑系统:windows 10

开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

工程版本:API 12

真机:Mate 60 Pro

语言:ArkTS、ArkUI

【3】算法分析

1. 角度差计算算法

计算当前角度与目标角度之间的差值,考虑了角度的周期性(0度和360度等效)。

private calculateAngleDifference(currentAngle: number, targetAngle: number): number {let diff = targetAngle - currentAngle;if (diff > 180) {diff -= 360; // 顺时针旋转超过180度,调整为负值} else if (diff < -180) {diff += 360; // 逆时针旋转超过180度,调整为正值}return diff;
}

2. 累计旋转角度算法

累计计算旋转角度,确保角度在0到360度之间。以便旋转动画能正确实现

private updateRotationAngle(angleDifference: number, newAngle: number): void {this.cumulativeRotation += angleDifference; // 累加旋转角度this.rotationAngle += angleDifference; // 更新当前旋转角度this.currentAngle = newAngle; // 更新当前传感器角度this.rotationAngle = (this.rotationAngle % 360 + 360) % 360; // 保持在0到360度之间
}

3. 方向计算算法

根据传感器角度计算当前方向,匹配角度范围对应的方向名称。

private calculateDirection(angle: number): string {for (const range of DIRECTION_RANGES) {if (angle >= range.min && angle < range.max) {return range.name; // 返回对应的方向名称}}return '未知方向'; // 如果角度不在任何范围内,返回未知方向
}

【完整代码】

import { sensor } from '@kit.SensorServiceKit'; // 导入传感器服务模块
import { BusinessError } from '@kit.BasicServicesKit'; // 导入业务错误处理模块// 定义方向范围类
class DirectionRange {name: string = ''; // 方向名称min: number = 0; // 最小角度max: number = 0; // 最大角度
}// 定义各个方向的范围
const DIRECTION_RANGES: DirectionRange[] = [{ name: '北', min: 337.5, max: 360 },{ name: '北', min: 0, max: 22.5 },{ name: '东北', min: 22.5, max: 67.5 },{ name: '东', min: 67.5, max: 112.5 },{ name: '东南', min: 112.5, max: 157.5 },{ name: '南', min: 157.5, max: 202.5 },{ name: '西南', min: 202.5, max: 247.5 },{ name: '西', min: 247.5, max: 292.5 },{ name: '西北', min: 292.5, max: 337.5 }
];// 定义指南针组件
@Entry
@Component
struct Compass {@State directionMessage: string = ''; // 当前方向的名称@State rotationAngle: number = 0; // 当前旋转角度@State currentAngle: number = 0; // 当前传感器角度@State cumulativeRotation: number = 0; // 累计旋转角度private threshold: number = 1; // 设置阈值,用于过滤小的旋转变化// 组件即将出现时调用aboutToAppear(): void {sensor.getSensorList((error: BusinessError) => {if (error) {console.error('获取传感器列表失败', error); // 如果获取传感器列表失败,打印错误信息return;}this.startOrientationUpdates(); // 开始监听传感器数据});}// 开始监听传感器的方位数据private startOrientationUpdates(): void {sensor.on(sensor.SensorId.ORIENTATION, (orientationData) => {const alpha = orientationData.alpha; // 获取当前的方位角this.directionMessage = this.calculateDirection(alpha); // 计算当前方向const angleDifference = this.calculateAngleDifference(this.currentAngle, alpha); // 计算角度差if (Math.abs(angleDifference) > this.threshold) { // 如果角度变化超过阈值this.updateRotationAngle(angleDifference, alpha); // 更新旋转角度}}, { interval: 10000000 }); // 设置传感器更新间隔,单位为纳秒,10000000表示1秒}// 计算两个角度之间的差异private calculateAngleDifference(currentAngle: number, targetAngle: number): number {let diff = targetAngle - currentAngle; // 计算角度差if (diff > 180) {diff -= 360; // 顺时针旋转超过180度,调整为负值} else if (diff < -180) {diff += 360; // 逆时针旋转超过180度,调整为正值}return diff; // 返回调整后的角度差}// 更新旋转角度private updateRotationAngle(angleDifference: number, newAngle: number): void {this.cumulativeRotation += angleDifference; // 累加旋转角度this.rotationAngle += angleDifference; // 更新当前旋转角度this.currentAngle = newAngle; // 更新当前传感器角度// 动画更新animateToImmediately({}, () => {this.rotationAngle = this.cumulativeRotation; // 将旋转角度设置为累计旋转角度});console.log(`累计旋转角度: ${this.cumulativeRotation}`); // 打印累计旋转角度}// 根据角度计算方向private calculateDirection(angle: number): string {for (const range of DIRECTION_RANGES) {if (angle >= range.min && angle < range.max) {return range.name; // 返回对应的方向名称}}return '未知方向'; // 如果角度不在任何范围内,返回未知方向}// 构建用户界面build() {Column({ space: 20 }) { // 创建一个列布局,设置间距为20Row({ space: 5 }) { // 创建一个行布局,设置间距为5Text(this.directionMessage) // 显示当前方向.layoutWeight(1) // 设置布局权重.textAlign(TextAlign.End) // 文本对齐方式.fontColor('#dedede') // 文本颜色.fontSize(50); // 文本大小Text(`${Math.floor(this.currentAngle)}°`) // 显示当前角度.layoutWeight(1) // 设置布局权重.textAlign(TextAlign.Start) // 文本对齐方式.fontColor('#dedede') // 文本颜色.fontSize(50); // 文本大小}.width('100%').margin({ top: 50 }); // 设置宽度和上边距Stack() { // 创建一个堆叠布局Stack() { // 内部堆叠布局Circle() // 创建一个圆形.width(250) // 设置宽度.height(250) // 设置高度.fillOpacity(0) // 设置填充透明度.strokeWidth(25) // 设置边框宽度.stroke('#f95941') // 设置边框颜色.strokeDashArray([1, 5]) // 设置边框虚线样式.strokeLineJoin(LineJoinStyle.Round); // 设置边框连接方式Text('北') // 创建一个文本,显示“北”.height('100%') // 设置高度.width(40) // 设置宽度.align(Alignment.Top) // 设置对齐方式.fontColor('#ff4f3f') // 设置文本颜色.rotate({ angle: 0 }) // 设置旋转角度.padding({ top: 80 }) // 设置内边距.textAlign(TextAlign.Center); // 设置文本对齐方式Text('东') // 创建一个文本,显示“东”.height('100%') // 设置高度.width(40) // 设置宽度.align(Alignment.Top) // 设置对齐方式.fontColor('#fcfdfd') // 设置文本颜色.rotate({ angle: 90 }) // 设置旋转角度.padding({ top: 80 }) // 设置内边距.textAlign(TextAlign.Center); // 设置文本对齐方式Text('南') // 创建一个文本,显示“南”.height('100%') // 设置高度.width(40) // 设置宽度.align(Alignment.Top) // 设置对齐方式.fontColor('#fcfdfd') // 设置文本颜色.rotate({ angle: 180 }) // 设置旋转角度.padding({ top: 80 }) // 设置内边距.textAlign(TextAlign.Center); // 设置文本对齐方式Text('西') // 创建一个文本,显示“西”.height('100%') // 设置高度.width(40) // 设置宽度.align(Alignment.Top) // 设置对齐方式.fontColor('#fcfdfd') // 设置文本颜色.rotate({ angle: 270 }) // 设置旋转角度.padding({ top: 80 }) // 设置内边距.textAlign(TextAlign.Center); // 设置文本对齐方式}.width('100%') // 设置宽度.height('100%') // 设置高度.borderRadius('50%') // 设置圆角.margin({ top: 50 }) // 设置上边距.rotate({ angle: -this.rotationAngle }) // 设置旋转角度.animation({}); // 设置动画效果Line() // 创建一个线条.width(5) // 设置宽度.height(40) // 设置高度.backgroundColor('#fdfffe') // 设置背景颜色.borderRadius('50%') // 设置圆角.margin({ bottom: 200 }); // 设置下边距}.width(300) // 设置宽度.height(300); // 设置高度}.height('100%') // 设置高度.width('100%') // 设置宽度.backgroundColor('#18181a'); // 设置背景颜色}
}

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

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

相关文章

人工智能的发展与未来:从Yann LeCun的观点谈起

引言 在当今的人工智能&#xff08;AI&#xff09;领域&#xff0c;AGI&#xff08;通用人工智能&#xff09;已成为热门话题。许多专家认为&#xff0c;随着技术的不断发展&#xff0c;AGI的实现只是时间问题。然而&#xff0c;Yann LeCun——图灵奖得主、Meta首席AI科学家&a…

【The Art of Unit Testing 3_自学笔记06】3.4 + 3.5 单元测试核心技能之:函数式注入与模块化注入的解决方案简介

文章目录 3.4 函数式依赖注入技术 Functional injection techniques3.5 模块化依赖注入技术 Modular injection techniques 写在前面 上一篇的最后部分对第三章后续内容做了一个概括性的梳理&#xff0c;并给出了断开依赖项的最简单的实现方案&#xff0c;函数参数值注入法。本…

电磁兼容(EMC):整改案例(六)Y电容过大导致雷击浪涌炸机

目录 1. 异常现象 2. 原因分析 3. 整改方案 4. 总结 1. 异常现象 某金属外壳带接地线的产品按GB/T 17626.5进行雷击浪涌测试&#xff0c;在L&#xff0c;N线对PE进行4kV浪涌电压测试时&#xff0c;出现炸机现象&#xff0c;AC-DC电源芯片损坏。而在L&#xff0c;N线间进行2…

代码之眼,陈欣的xml解密之路

第一章 在未来的世界里&#xff0c;科技已经发展到了令人难以想象的地步。人工智能、量子计算和生物技术交织在一起&#xff0c;创造了一个全新的社会形态。在这个世界中&#xff0c;有一个名为“代码守护者”的组织&#xff0c;专门负责维护全球信息系统的安全和稳定。 陈欣是…

L0G1000:Linux+InternStudio 闯关作业

1. 配置基础环境 首先&#xff0c;打开 Intern Studio 界面&#xff0c;点击 创建开发机 配置开发机系统。 InternStudio 填写 开发机名称 后&#xff0c;点击 选择镜像 使用 Cuda11.7-conda 镜像&#xff0c;然后在资源配置中&#xff0c;使用 10% A100 * 1 的选项&#xff…

爬虫笔记22——当当网图书详情页静、动态数据爬取

当当网动态数据爬取 静态数据爬取动态数据爬取接口参数的获取 静态数据爬取 进入图书详情&#xff0c;这里的图书数据信息比如标题、价格、图片都是非结构化数据&#xff0c;可以使用xpath语法提取。是很简单的数据采集了&#xff0c;就不细说了。 动态数据爬取 滑到下面这里的…

使用pathview在线渲染KEGG Pathway Map,给感兴趣的基因、化合物添加颜色

导读&#xff1a; 通过将用户提供的基因表达定量数据&#xff0c;化合物定量数据映射并渲染到相关的KEGG通路图上&#xff0c;能够帮助我们直观且系统地研究基因、酶、化合物间的关系。 KEGG通路图简介 KEGG PATHWAY数据库是一系列手动绘制的图形图谱的集合&#xff0c;称为…

自动化测试工具Ranorex Studio(二十一)-适配一个已存在的对象库

通过录制一个手工测试场景我们创建了一个对象库。录制期间用到的每个UI元素都在库中创建了一个新的条目。默认情况下&#xff0c;一个新的Ranorex Studio项目包含一个库文件(*.rxrep)&#xff0c;这个文件可以被多个录制模块或代码模块使用。 图&#xff1a;一个库的文件视图…

OpenSLL下载,环境变量配置

https://slproweb.com/products/Win32OpenSSL.html 环境变量 新建一个path为安装选择的目录的bin路径

【MyBatis】【基于轻量型架构的WEB开发】课程 课后习题 章节测试

mybatis关联查询、缓存、注解 一. 单选题 1. 下列关于 <collection> 元素的描述正确的是&#xff08;&#xff09;。 A. MyBatis 就是通过 <collection> 元素来处理一对多关联关系的 B. <collection> 元素的属性与 <association> 元素完全相同 C.…

JavaEE-多线程上

文章目录 线程概述进程/线程多线程的作用JVM关于线程资源的规范关于Java程序的运行原理 并发与并行并发(concurrency)并行(parallellism)并发编程与并行编程 线程的调度策略分时调度模型抢占式调度模型 创建线程线程类分析入门实现线程的第一种方式实现线程的第二种方式 线程的…

SQL 常用语句

目录 我的测试环境 学习文档 进入数据库 基础通关测验 语句-- 查 展示数据库&#xff1b; 进入某个数据库&#xff1b; 展示表&#xff1a; 展示某个表 desc 查询整个表&#xff1a; 查询特定列&#xff1a; 范围查询 等于特定值 不等于 介于 特定字符查询 Li…

[MySQL]DQL语句(一)

查询语句是数据库操作中最为重要的一系列语法。查询关键字有 select、where、group、having、order by、imit。其中imit是MySQL的方言&#xff0c;只在MySQL适用。 数据库查询又分单表查询和多表查询&#xff0c;这里讲一下单表查询。 基础查询 # 查询指定列 SELECT * FROM …

【Unity】鼠标点击获取世界坐标位置:物体移动至鼠标点击的位置

需求说明 鼠标点击3D场景时&#xff0c;可以获取其所在的世界坐标&#xff1b; 鼠标点击3D物体时&#xff0c;可以获取该物体&#xff1b; 鼠标点击3D物体时&#xff0c;可以让玩家移动至该物体&#xff1b; 成果展示 Scene部分 关于仓库栏的设置&#xff0c;物体如何进入…

使用nvm切换node版本失败

​ 使用nvm切换node版本失败&#xff08;原node版本v20.14.0&#xff0c;我使用nvm use 16.9.1切换node版本后&#xff0c;显示Now using node v16.9.1可当我使用命令node -v查看当前node版本时还是v20.14.0&#xff0c;意味着版本切换失败&#xff09;&#xff1a; 这个原因大…

Hive数据库操作语法

数据类型 内部表和外部表 内部表 &#xff08;CREATE TABLE table_name ......&#xff09;未被external关键字修饰的即是内部表&#xff0c; 即普通表。 内部表又称管理表,内部表数据存储的位置由hive.metastore.warehouse.dir参数决定&#xff08;默认&#xff1a;/user/h…

【Python TensorFlow】入门到精通

TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google 开发&#xff0c;广泛应用于机器学习和深度学习领域。本篇将详细介绍 TensorFlow 的基础知识&#xff0c;并通过一系列示例来帮助读者从入门到精通 TensorFlow 的使用。 1. TensorFlow 简介 1.1 什么是 TensorFlow…

设计模式08-行为型模式1(命令模式/迭代器模式/观察者模式/Java)

五、行为型模式 **行为模式的定义&#xff1a;**行为型模式是对不同的对象之间划分职责和算法的抽象化。行为型模式定义了系统中对象之间的交互与通信&#xff0c;研究系统在运行时对象之间的相互通信与协作&#xff0c;进一步明确对象的职责&#xff0c;包括对系统中较为复杂的…

服务器作业2

关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 配置文件 创建用户nfs-upload [rootlocalhost ~]# useradd -u 210 nfs-upload [rootlocalhost ~]# groupmod -g 210 nfs-upload 创建tom用户 [rootlocalhost ~]# useradd tom 查看to…

【数据结构】堆:建堆/向下调整/上向调整/堆排序/TOK问题

文章目录 前言堆的定义1.大小堆2.完全二叉树 堆的实现堆的数据结构初始化销毁取堆顶元素判断堆是否为空父结点和子结点下标关系&#xff08;重要&#xff09; 向下调整法-O(n)小堆版大堆版 向上调整法-nlog(n)堆的插入和删除插入(调用向上调整)删除(调用向下调整) 构建最大堆向…