当前位置: 首页 > java >正文

鸿蒙运动开发实战:打造 Keep 式轨迹播放效果

前言

在运动类应用中,轨迹播放效果是提升用户体验的关键功能之一。它不仅能直观展示用户的运动路线,还能通过动态效果增强运动的趣味性。Keep 作为一款知名的运动健身应用,其轨迹播放效果深受用户喜爱。那么,如何在鸿蒙系统中开发出类似 Keep 的轨迹播放效果呢?本文将通过实际代码案例,深入解析实现这一功能的关键步骤和技术要点。

效果:

在这里插入图片描述

一、核心功能拆解

要实现类似 Keep 的轨迹播放效果,我们需要完成以下几个核心功能:

• 动态轨迹播放:通过定时器和动画效果,实现轨迹的动态播放,模拟用户运动过程。

• 地图交互:在地图上绘制轨迹,并根据播放进度更新地图中心点和旋转角度。

二、动态轨迹播放

1.播放逻辑

通过定时器和动画效果实现轨迹的动态播放。以下是播放轨迹的核心代码:

private playTrack() {// 如果已经在播放,则停止if (this.playTimer) {this.mapController?.removeOverlay(this.polyline);clearInterval(this.playTimer);this.playTimer = undefined;if (this.animationTimer) {clearInterval(this.animationTimer);}if (this.movingMarker) {this.mapController?.removeOverlay(this.movingMarker);this.movingMarker = undefined;}this.currentPointIndex = 0;return;}// 创建动态位置标记this.movingMarker = new Marker({position: this.trackPoints[0],icon: new ImageEntity("rawfile://images/ic_run_detail_start.png"),isJoinCollision: SysEnum.CollisionBehavior.NOT_COLLIDE,located: SysEnum.Located.CENTER});this.mapController?.addOverlay(this.movingMarker);// 开始播放this.playTimer = setInterval(() => {this.currentPointIndex++;if (this.currentPointIndex >= this.trackPoints.length) {clearInterval(this.playTimer);this.playTimer = undefined;this.currentPointIndex = 0;if (this.movingMarker) {this.mapController?.removeOverlay(this.movingMarker);this.movingMarker = undefined;}return;}// 更新动态位置标记位置,使用setInterval实现平滑移动if (this.movingMarker && this.currentPointIndex < this.trackPoints.length - 1) {const currentPoint = this.trackPoints[this.currentPointIndex];const nextPoint = this.trackPoints[this.currentPointIndex + 1];let animationProgress = 0;// 清除之前的动画定时器if (this.animationTimer) {clearInterval(this.animationTimer);}// 创建新的动画定时器,每10ms更新一次位置this.animationTimer = setInterval(() => {animationProgress += 0.1; // 每次增加0.1的进度if (animationProgress >= 1) {clearInterval(this.animationTimer);this.animationTimer = undefined;this.movingMarker?.setPosition(new LatLng(nextPoint.lat, nextPoint.lng));} else {const interpolatedLat = currentPoint.lat + (nextPoint.lat - currentPoint.lat) * animationProgress;const interpolatedLng = currentPoint.lng + (nextPoint.lng - currentPoint.lng) * animationProgress;this.movingMarker?.setPosition(new LatLng(interpolatedLat, interpolatedLng));}}, 10); // 每10ms执行一次}// 绘制当前轨迹线段const currentPoints = this.trackPoints.slice(0, this.currentPointIndex + 1);const currentColors = PathGradientTool.getPathColors(this.record!.points.slice(0, this.currentPointIndex + 1), 100);if (this.polyline) {this.mapController?.removeOverlay(this.polyline);this.polyline.remove();this.polyline.destroy();}this.polyline = new Polyline({points: currentPoints,width: 5,join: SysEnum.LineJoinType.ROUND,cap: SysEnum.LineCapType.ROUND,isGradient: true,colorList: currentColors!});this.mapController?.addOverlay(this.polyline);// 更新地图中心点和旋转角度let bearing = 0;if (this.currentPointIndex < this.trackPoints.length - 1) {const currentPoint = this.trackPoints[this.currentPointIndex];const nextPoint = this.trackPoints[this.currentPointIndex + 1];bearing = Math.atan2(nextPoint.lat - currentPoint.lat,nextPoint.lng - currentPoint.lng) * 180 / Math.PI;bearing = (bearing + 360) % 360;bearing = (360 - bearing + 90) % 360;}this.mapController?.mapStatus.setRotate(bearing).setOverlooking(90).setCenterPoint(new LatLng(this.trackPoints[this.currentPointIndex].lat, this.trackPoints[this.currentPointIndex].lng)).refresh();}, 100); // 每100ms移动一次
}

2.动画效果

通过定时器和线性插值实现动态轨迹的平滑移动效果。以下是动画效果的核心代码:

if (this.movingMarker && this.currentPointIndex < this.trackPoints.length - 1) {const currentPoint = this.trackPoints[this.currentPointIndex];const nextPoint = this.trackPoints[this.currentPointIndex + 1];let animationProgress = 0;// 清除之前的动画定时器if (this.animationTimer) {clearInterval(this.animationTimer);}// 创建新的动画定时器,每10ms更新一次位置this.animationTimer = setInterval(() => {animationProgress += 0.1; // 每次增加0.1的进度if (animationProgress >= 1) {clearInterval(this.animationTimer);this.animationTimer = undefined;this.movingMarker?.setPosition(new LatLng(nextPoint.lat, nextPoint.lng));} else {const interpolatedLat = currentPoint.lat + (nextPoint.lat - currentPoint.lat) * animationProgress;const interpolatedLng = currentPoint.lng + (nextPoint.lng - currentPoint.lng) * animationProgress;this.movingMarker?.setPosition(new LatLng(interpolatedLat, interpolatedLng));}}, 10); // 每10ms执行一次
}

三、地图交互

1.地图中心点和旋转角度更新

在播放轨迹的过程中,动态更新地图的中心点和旋转角度,以确保用户始终能看到当前播放的位置。以下是更新地图中心点和旋转角度的代码:

let bearing = 0;
if (this.currentPointIndex < this.trackPoints.length - 1) {const currentPoint = this.trackPoints[this.currentPointIndex];const nextPoint = this.trackPoints[this.currentPointIndex + 1];bearing = Math.atan2(nextPoint.lat - currentPoint.lat,nextPoint.lng - currentPoint.lng) * 180 / Math.PI;bearing = (bearing + 360) % 360;bearing = (360 - bearing + 90) % 360;
}this.mapController?.mapStatus.setRotate(bearing).setOverlooking(90).setCenterPoint(new LatLng(this.trackPoints[this.currentPointIndex].lat, this.trackPoints[this.currentPointIndex].lng)).refresh();

四、总结

通过上述步骤,我们成功实现了类似 Keep 的轨迹播放效果。不仅提升了用户体验,还为运动数据的可视化提供了有力支持。

http://www.xdnf.cn/news/9381.html

相关文章:

  • Java Stream API 终止操作的详细解析
  • QML之Canvas
  • 数组名的大小理解
  • <b> 与 <span> 等行内元素添加 margin-top 或 margin-bottom 不生效问题
  • CarPropertyService 介绍
  • 【FAQ】spring boot 3 集成 nacos
  • pgsql 查看每张表大小
  • 创建vue项目
  • 3D Web轻量化引擎HOOPS Communicator实时协作功能深度解析
  • 小黑黑大模型应用日常摸索中:初次使用langchain智能体调用工具,准备继续深入
  • 题解——相交链表(力扣160 easy)
  • Java研学-MybatisPlus(三)
  • 磁盘管理练习题
  • 《Python基础》第1期:人生苦短,我用Python
  • Java基础 5.27
  • Oracle初识
  • 遗传算法简明指南:思路解析与C++实现
  • C++优先队列(priority_queue)使用详解
  • 计算机系统结构-第四章节-背诵
  • 使用Auto-Coder对js文件进行审计并修复漏洞1.3 1.4 1.5版本
  • BugKu Web渗透之Post
  • Python 实现简易版的文件管理(结合网络编程)
  • linux kernel 内存回收水位线调整方法
  • 第九章 Java基础-集合
  • 鸿蒙OSUniApp 制作简洁的用户个人中心页面#三方框架 #Uniapp
  • 【Springboot+LangChain4j】实现多轮对话,即记忆对话功能
  • v4.0 论文投稿-Latex论文投稿注意事项
  • 基于Alibaba Cloud Linux + 宝塔面板安装 LibreOffice 全攻略流程
  • 怎么实现pid隔离
  • 海信IP810N-72UB0贵州联通原机分区备份包