HarmonyOS鸿蒙NEXT中经纬度距离计算
HarmonyOS鸿蒙NEXT中经纬度距离计算 HarmonyOS NEXT 经纬度距离计算分享
功能概述
本组件基于HarmonyOS的MapKit实现地理坐标距离计算功能,通过@Entry和@Component装饰器构建的标准应用组件,实现了经纬度输入、距离计算、交互反馈等完整功能链路。组件采用模块化设计,具有清晰的UI层级和稳健的业务逻辑。
核心功能实现
坐标输入体系
- 双输入组架构:独立设置起点/终点的经纬度输入(经度:-180~180,纬度:-90~90)
- 智能输入验证:@State @Watch(‘onInputChange’) private startLongitude: string = “” // 响应式数据绑定
- @State @Watch(‘onInputChange’) private endLatitude: string = “”
实现效果

环境准备
- 操作系统:Windows 10
- 开发工具:DevEco Studio(5.0.7.210)
- 目标设备:华为Mate60 Pro
- 开发语言:ArkTS
- 框架:ArkUI
- API版本:API 14
工程目录
├─ AppScope // 全局应用资源目录(跨模块共享)
│ ├─ app.json5 // 全局配置文件(应用基础信息/权限声明)
│ └─ resources
│ └─ base
│ ├─ element // 多语言字符串资源
│ └─ media // 全局媒体资源(应用图标等)
├─ entry // 主模块(核心业务模块)
│ ├─ src/main/ets
│ │ ├─ entryability
│ │ ├─ entrybackupability
│ │ └─ pages
│ │ └─ Index.ets
│ │
│ ├─ resources
│ │ ├─ base
│ │ ├─ dark
│ │ └─ rawfile
具体实现
1. 坐标输入系
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private startLongitude: string = "";
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private endLatitude: string = "";
- 双向绑定机制:通过@Watch装饰器建立属性与onInputChange方法的监听关系,任何输入变化立即触发距离重算
- 类型安全转换:使用Number()进行显式类型转换,确保地理坐标数值有效性
- 输入约束:
.type(InputType.NUMBER_DECIMAL) // 强制数字键盘
.borderColor(this.isStartFocused ? ... ) // 动态视觉反馈
2. 距离计算引擎
map.calculateDistance(fromLatLng, toLatLng);
- 算法实现:基于Haversine公式计算球面距离(实际调用地图服务SDK)
- 单位转换:
${(this.distance / 1000).toFixed(2)} // 米转公里+两位小数
- 实时计算策略:每次输入变化后立即重新计算,保证结果实时性
完整代码
import { mapCommon } from '@kit.MapKit'; // 导入地图通用模块
import { map } from '@kit.MapKit'; // 导入地图模块
@Entry // 入口装饰器,标识该组件为应用的入口
@Component // 组件装饰器,定义一个组件
struct DistanceCalculator {
[@State](/user/State) private primaryColor: string = '#fea024'; // 定义主题颜色,初始值为橙色
[@State](/user/State) private fontColor: string = "#2e2e2e"; // 定义字体颜色,初始值为深灰色
[@State](/user/State) private isStartFocused: boolean = false; // 定义起点输入框的聚焦状态,初始为 false
[@State](/user/State) private isEndFocused: boolean = false; // 定义终点输入框的聚焦状态,初始为 false
[@State](/user/State) private isSecondStartFocused: boolean = false; // 定义第二起点输入框的聚焦状态,初始为 false
[@State](/user/State) private isSecondEndFocused: boolean = false; // 定义第二终点输入框的聚焦状态,初始为 false
[@State](/user/State) private baseSpacing: number = 30; // 定义基础间距,初始值为 30
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private startLongitude: string = ""; // 定义起点经度,初始为空,并监视输入变化
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private startLatitude: string = ""; // 定义起点纬度,初始为空,并监视输入变化
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private endLongitude: string = ""; // 定义终点经度,初始为空,并监视输入变化
[@State](/user/State) [@Watch](/user/Watch)('onInputChange') private endLatitude: string = ""; // 定义终点纬度,初始为空,并监视输入变化
[@State](/user/State) distance: number = 0; // 定义两点之间的距离,初始值为 0
[@State](/user/State) MyColor:string = '#808e96'
aboutToAppear(): void { // 生命周期钩子函数,组件即将显示时调用
this.onInputChange(); // 调用输入变化处理函数以初始化
}
onInputChange() { // 输入变化处理函数
let fromLatLng: mapCommon.LatLng = { // 创建起点经纬度对象
latitude: Number(this.startLatitude), // 将起点纬度转换为数字
longitude: Number(this.startLongitude) // 将起点经度转换为数字
};
let toLatLng: mapCommon.LatLng = { // 创建终点经纬度对象
latitude: Number(this.endLatitude), // 将终点纬度转换为数字
longitude: Number(this.endLongitude) // 将终点经度转换为数字
};
this.distance = map.calculateDistance(fromLatLng, toLatLng); // 计算起点和终点之间的距离
}
build() { // 构建界面函数
Column() { // 垂直布局容器
Text("经纬度距离计算")
.borderRadius(10)// 创建文本组件,显示标题
.width('95%') // 设置宽度为 100%
.height(50) // 设置高度为 54 像素
.fontSize(30) // 设置字体大小为 18
.fontWeight(600) // 设置字体粗细为 600
.backgroundColor(this.MyColor) // 设置背景颜色为白色
.textAlign(TextAlign.Center) // 设置文本对齐方式为居中
.fontColor(this.fontColor); // 设置字体颜色为定义的字体颜色
// 输入区域
Column() { // 垂直布局容器
Row() { // 水平布局容器
Text('示例(北京-->上海)') // 创建文本组件,显示示例信息
.fontColor(this.MyColor) // 设置字体颜色为蓝色
.fontSize(18) // 设置字体大小为 18
.padding(`${this.baseSpacing / 2}lpx`) // 设置内边距
.backgroundColor("#f2f1fd") // 设置背景颜色
.borderRadius(5) // 设置圆角半径为 5
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) // 设置点击效果
.onClick(() => { // 点击事件处理
this.startLongitude = "116.4074"; // 设置起点经度为北京经度
this.startLatitude = "39.9042"; // 设置起点纬度为北京纬度
this.endLongitude = "121.4737"; // 设置终点经度为上海经度
this.endLatitude = "31.2304"; // 设置终点纬度为上海纬度
});
Blank(); // 占位符,用于占据空间
Text('清空') // 创建文本组件,显示“清空”按钮
.fontColor(Color.Red) // 设置字体颜色为橙色
.fontSize(18) // 设置字体大小为 18
.padding(`${this.baseSpacing / 2}lpx`) // 设置内边距
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) // 设置点击效果
.backgroundColor("#ffefe6") // 设置背景颜色
.borderRadius(5) // 设置圆角半径为 5
.onClick(() => { // 点击事件处理
this.startLongitude = ""; // 清空起点经度
this.startLatitude = ""; // 清空起点纬度
this.endLongitude = ""; // 清空终点经度
this.endLatitude = ""; // 清空终点纬度
});
}.height(45) // 设置行高为 45 像素
.justifyContent(FlexAlign.SpaceBetween) // 设置子元素在主轴上的对齐方式
.width('100%'); // 设置宽度为 100%
Divider().margin({ top: 5, bottom: 5 }); // 创建分隔符,设置上下边距
// 起点输入
Row() { // 水平布局容器
Text('设置起点') // 创建文本组件,显示“起点”
.fontWeight(600) // 设置字体粗细为 600
.fontSize(18) // 设置字体大小为 18
.fontColor(this.fontColor); // 设置字体颜色为定义的字体颜色
}
.margin({top:5})
Row() { // 水平布局容器
TextInput({ text: $$this.startLongitude, placeholder: '输入经度' }) // 创建起点经度输入框
.caretColor(this.primaryColor) // 设置光标颜色为主题颜色
.layoutWeight(1) // 设置布局权重
.type(InputType.NUMBER_DECIMAL) // 设置输入类型为小数
.placeholderColor(this.isStartFocused ? this.primaryColor : Color.Gray) // 设置占位符颜色
.fontColor(this.isStartFocused ? this.primaryColor : this.fontColor) // 设置字体颜色
.borderColor(this.isStartFocused ? this.primaryColor : Color.Gray) // 设置边框颜色
.borderWidth(1) // 设置边框宽度
.borderRadius(10) // 设置圆角半径为 10
.backgroundColor(Color.White) // 设置背景颜色为白色
.showUnderline(false) // 不显示下划线
.onBlur(() => this.isStartFocused = false) // 失去焦点时设置聚焦状态为 false
.onFocus(() => this.isStartFocused = true); // 获得焦点时设置聚焦状态为 true
Line().width(10); // 创建分隔符,设置宽度为 10 像素
TextInput({ text: $$this.startLatitude, placeholder: '输入纬度' }) // 创建起点纬度输入框
.caretColor(this.primaryColor) // 设置光标颜色为主题颜色
.layoutWeight(1) // 设置布局权重
.type(InputType.NUMBER_DECIMAL) // 设置输入类型为小数
.placeholderColor(this.isEndFocused ? this.primaryColor : Color.Gray) // 设置占位符颜色
.fontColor(this.isEndFocused ? this.primaryColor : this.fontColor) // 设置字体颜色
.borderColor(this.isEndFocused ? this.primaryColor : Color.Gray) // 设置边框颜色
.borderWidth(1) // 设置边框宽度
.borderRadius(10) // 设置圆角半径为 10
.backgroundColor(Color.White) // 设置背景颜色为白色
.showUnderline(false) // 不显示下划线
.onBlur(() => this.isEndFocused = false) // 失去焦点时设置聚焦状态为 false
.onFocus(() => this.isEndFocused = true); // 获得焦点时设置聚焦状态为 true
}
.margin({top:3})
// 终点输入
Text('设置终点') // 创建文本组件,显示“终点”
.fontWeight(600) // 设置字体粗细为 600
.fontSize(18) // 设置字体大小为 18
.fontColor(this.fontColor) // 设置字体颜色为定义的字体颜色
.margin({top:15})
Row() { // 水平布局容器
TextInput({ text: $$this.endLongitude, placeholder: '输入经度' }) // 创建终点经度输入框
.caretColor(this.primaryColor) // 设置光标颜色为主题颜色
.layoutWeight(1) // 设置布局权重
.type(InputType.NUMBER_DECIMAL) // 设置输入类型为小数
.placeholderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray) // 设置占位符颜色
.fontColor(this.isSecondStartFocused ? this.primaryColor : this.fontColor) // 设置字体颜色
.borderColor(this.isSecondStartFocused ? this.primaryColor : Color.Gray) // 设置边框颜色
.borderWidth(1) // 设置边框宽度
.borderRadius(10) // 设置圆角半径为 10
.backgroundColor(Color.White) // 设置背景颜色为白色
.showUnderline(false) // 不显示下划线
.onBlur(() => this.isSecondStartFocused = false) // 失去焦点时设置聚焦状态为 false
.onFocus(() => this.isSecondStartFocused = true); // 获得焦点时设置聚焦状态为 true
Line().width(10); // 创建分隔符,设置宽度为 10 像素
TextInput({ text: $$this.endLatitude, placeholder: '输入纬度' }) // 创建终点纬度输入框
.caretColor(this.primaryColor) // 设置光标颜色为主题颜色
.layoutWeight(1) // 设置布局权重
.type(InputType.NUMBER_DECIMAL) // 设置输入类型为小数
.placeholderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray) // 设置占位符颜色
.fontColor(this.isSecondEndFocused ? this.primaryColor : this.fontColor) // 设置字体颜色
.borderColor(this.isSecondEndFocused ? this.primaryColor : Color.Gray) // 设置边框颜色
.borderWidth(1) // 设置边框宽度
.borderRadius(10) // 设置圆角半径为 10
.backgroundColor(Color.White) // 设置背景颜色为白色
.showUnderline(false) // 不显示下划线
.onBlur(() => this.isSecondEndFocused = false) // 失去焦点时设置聚焦状态为 false
.onFocus(() => this.isSecondEndFocused = true); // 获得焦点时设置聚焦状态为 true
}
.margin({top:3})
}
.height('35%')
.width('95%') // 设置输入区域宽度为 650 像素
.padding(`${this.baseSpacing}lpx`) // 设置内边距
.margin({ top: 20 }) // 设置上边距为 20 像素
.backgroundColor(this.MyColor) // 设置背景颜色为白色
.borderRadius(10) // 设置圆角半径为 10
.alignItems(HorizontalAlign.Start); // 设置子元素在交叉轴上的对齐方式
// 显示计算结果
Column() { // 垂直布局容器
Text() { // 文本组件
Span(`两点之间的距离是:`) // 创建文本片段,显示提示信息
Span(`${(this.distance / 1000).toFixed(2)}`).fontColor(this.primaryColor) // 创建文本片段,显示距离(公里),并设置颜色
Span(`公里`) // 创建文本片段,显示单位“公里”
}
.fontWeight(600) // 设置字体粗细为 600
.fontSize(18) // 设置字体大小为 18
.fontColor(this.fontColor); // 设置字体颜色为定义的字体颜色
}
.width('95%') // 设置结果显示区域宽度为 650 像素
.backgroundColor(this.MyColor) // 设置背景颜色为白色
.borderRadius(10) // 设置圆角半径为 10
.padding(`${this.baseSpacing}lpx`) // 设置内边距
.margin({ top: `${this.baseSpacing}lpx` }) // 设置上边距
.alignItems(HorizontalAlign.Start); // 设置子元素在交叉轴上的对齐方式
}
.height('100%') // 设置整个组件高度为 100%
.width('100%') // 设置整个组件宽度为 100%
.backgroundColor("#eff0f3"); // 设置背景颜色为浅灰色
}
}
更多关于HarmonyOS鸿蒙NEXT中经纬度距离计算的实战教程也可以访问 https://www.itying.com/category-93-b0.html
2 回复
在HarmonyOS鸿蒙NEXT中,经纬度距离计算可以通过使用Geolocation模块实现。该模块提供了计算两个地理坐标点之间距离的方法。具体步骤如下:
-
导入模块:首先需要导入
[@ohos](/user/ohos).geolocation模块。import geolocation from '[@ohos](/user/ohos).geolocation'; -
定义坐标点:定义两个地理坐标点,每个点包含经度和纬度。
let point1 = { latitude: 39.9042, longitude: 116.4074 }; // 北京 let point2 = { latitude: 31.2304, longitude: 121.4737 }; // 上海 -
计算距离:使用
geolocation.getDistance方法计算两个点之间的距离。let distance = geolocation.getDistance(point1, point2); -
获取结果:
getDistance方法返回的距离单位是米。console.log("Distance between Beijing and Shanghai: " + distance + " meters");
更多关于HarmonyOS鸿蒙NEXT中经纬度距离计算的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙NEXT中,计算两个经纬度点之间的距离可以使用Haversine公式。以下是一个简单的实现示例:
public class DistanceCalculator {
private static final double EARTH_RADIUS = 6371; // 地球半径,单位:千米
public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
}
}
此代码计算两个经纬度点之间的直线距离,单位为千米。

