本示例使用 geoLocationManager 进行地理位置定位和地理信息获取,并利用 MapComponent 组件展示地图,添加用户位置和打卡范围,通过计算用户位置和打卡中心点的距离判断用户是否处于打卡区域,实现了打卡功能。
使用说明
注意:本示例需要打开位置定位和联网使用。
使用本示例前,需要先完成以下准备工作。
ClockInComponent是一个用于显示地图、获取用户位置、判断用户是否在打卡范围内的自定义功能组件。它使用了MapComponent组件来显示地图,geoLocationManager接口来获取用户位置,并通过计算用户位置与打卡圆心之间的距离来判断用户是否在打卡范围内。
// 地图初始化参数,设置地图中心点坐标及层级
mapOptions: mapCommon.MapOptions = {
position: {
target: {
latitude: 39.9,
longitude: 116.4
},
zoom: 14
}
};
MapComponent({
mapOptions: this.mapOptions,
mapCallback: this.mapCallback,
customInfoWindow: (markerDelegate: map.MarkerDelegate) => {
this.customInfoWindowBuilder(markerDelegate);
}
})
initMap() {
// 地图初始化的回调
this.mapCallback = async (err, mapController) => {
if (!err) {
// 获取地图控制器,用来操作地图
this.mapController = mapController;
if (this.getMapController) {
this.getMapController(this.mapController);
}
// 获取地图监听事件管理器
this.mapEventManager = this.mapController.getEventManager();
// 隐藏缩放控件
this.mapController.setZoomControlsEnabled(false);
// 设置地图和边界的距离
this.mapController.setPadding(this.mapPadding);
// ...
} else {
logger.error(TAG, `mapcomponent init failed, error message: ${err.message}, error code: ${err.code}`);
}
};
}
initMap() {
// 地图初始化的回调
this.mapCallback = async (err, mapController) => {
if (!err) {
// ...
let callback = () => {
// 验证用户是否授予定位权限,无权限则在首次启动时弹出权限申请对话框
this.reqPermissionFromUser().then(async (grantStatus) => {
// ...
}).catch((err: BusinessError) => {
logger.error(TAG, `permission request failed, error message: ${err.message}, error code: ${err.code}`);
});
}
// 监听地图加载完成事件
this.mapEventManager.on('mapLoad', callback);
} else {
logger.error(TAG, `mapcomponent init failed, error message: ${err.message}, error code: ${err.code}`);
}
};
}
if (grantStatus) {
// 获取用户位置
await this.getUserCurrentLocation();
// 动画方式移动相机到用户位置,动画过程中设置显示标记信息窗会失效,需要等待动画结束
await this.animateMoveCamera(this.myPositionGCJ02, this.duration);
// 添加圆形打卡区域
await this.addCircle();
// 添加用户位置标记
this.marker = await this.mapController?.addMarker({
icon: this.markerIcon,
position: this.myPositionGCJ02,
draggable: false,
visible: true,
clickable: true, // 要显示信息窗口必须为true
zIndex: 15,
alpha: 1,
anchorU: 0.5,
anchorV: 1,
rotation: 0
});
// ...
}
/**
* 获取用户当前位置。
*/
async getUserCurrentLocation() {
this.myPositionWGS84 = await geoLocationManager.getCurrentLocation();
this.myPositionGCJ02 =
map.convertCoordinateSync(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, this.myPositionWGS84);
}
/**
* 判断用户是否在圆圈内。
* @param {LatLng} pos1 - 用户位置。
* @param {LatLng} pos2 - 圆心位置。
* @param {number} radius - 圆半径,单位为米。
*/
isUserInCircle(pos1: mapCommon.LatLng, pos2: mapCommon.LatLng, radius: number) {
const distance = map.calculateDistance(pos1, pos2);
this.isInArea = distance <= radius;
}
/**
* 设置标记信息。
*/
setMarkerInfo() {
if (this.myPositionWGS84) {
let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {
latitude: this.myPositionWGS84.latitude,
longitude: this.myPositionWGS84.longitude,
maxItems: 1 // 获取最近的一个地址
};
// 将坐标转换为地理描述
geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest).then((data) => {
if (this.marker && data[0].placeName) {
// 显示marker信息窗
this.marker.setTitle(data[0].placeName);
this.marker.setInfoWindowVisible(true);
}
}).catch((err: BusinessError) => {
logger.error(TAG, `addresser get failed, error message: ${err.message}, error code: ${err.code}`);
});
}
}
/**
* 添加用户位置监听。
*/
addLocationListener() {
let requestInfo: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.ACCURACY,
scenario: geoLocationManager.LocationRequestScenario.UNSET,
timeInterval: this.locationTimeInterval,
distanceInterval: 0,
maxAccuracy: 0
};
let locationChange = (location: geoLocationManager.Location): void => {
this.myPositionWGS84 = location;
this.myPositionGCJ02 =
map.convertCoordinateSync(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, location);
if (this.marker) {
this.animateMoveMarker(this.marker, this.myPositionGCJ02, this.duration);
}
// 位置变动时再次判断用户是否在打卡范围内
if (this.mapCircleOptions) {
this.isUserInCircle(this.myPositionGCJ02, this.mapCircleOptions.center, this.mapCircleOptions.radius);
}
};
geoLocationManager.on('locationChange', requestInfo, locationChange);
}
// ClockInModel.ets
/**
* ClockInController 类用于处理打卡相关的逻辑。
* 该控制器负责获取当前位置地址等功能。
*/
export class ClockInController {
/**
* 获取当前位置地址的方法。
* @returns {string} 当前位置的地址字符串。
*/
getAddress: () => string = () => '';
}
// ClockInComponent.ets
/**
* 获取当前位置地址。
* @returns {string} 当前位置的地址字符串。
*/
private getAddress = () => {
if (this.marker) {
return this.marker.getTitle();
}
return '';
}
欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案)
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
ClockInSamplePage基于ClockInComponent实现了完整的打卡场景,可通过传入参数控制打卡区域的位置和样式、定位按钮的显示隐藏、是否开启位置监听、用户位置信息窗口的内容和样式等,并且根据ClockInComponent中用户位置是否处于打卡范围的判断结果进行打卡操作及反馈。
ClockInComponent({
clockInController: this.clockInController,
isInArea: this.isInArea,
isLocationButtonVisible: this.isLocationButtonVisible,
locationButtonPosition: this.locationButtonPosition,
mapOptions: this.mapOptions,
getMapController: this.getController,
customInfoWindowSlotParam: this.customInfoWindowSlot
})
// 打卡按钮
Text(this.clockInButtonText)
.onClick(() => {
// 如果在打卡范围内,进行打卡操作,否则显示提示信息
if (this.isInArea) {
// 如果已有上班打卡信息,则进行下班打卡,否则新增上班打卡信息
if (this.clockInInfo) {
// 如果已有下班打卡信息,则更新下班打卡信息,否则新增下班打卡信息
this.clockOutInfo = {
time: this.timeFormat.format(new Date()),
address: this.clockInController.getAddress()
};
this.clockInButtonText = this.clockOutInfo !== null ? $r('app.string.clock_in_button_text_update') :
$r('app.string.clock_in_button_text_clock_out');
} else {
this.clockInInfo = {
time: this.timeFormat.format(new Date()),
address: this.clockInController.getAddress()
};
this.clockInButtonText = $r('app.string.clock_in_button_text_clock_out');
}
} else {
promptAction.showToast({
message: $r('app.string.clock_in_toast_message_out_of_range')
});
}
})
// ...
不涉及
clockin // har类型
|---/src/main/ets/components
| |---ClockInComponent.ets // 封装的打卡功能组件
|---/src/main/ets/model
| |---ClockInModel.ets // 数据模型层-打卡功能组件控制器与打卡信息数据模型
|---/src/main/ets/utils
| |---Constants.ets // 常量数据
| |---Logger.ets // 日志打印工具
|---/src/main/ets/views
| |---ClockInSamplePage.ets // 视图层-打卡场景主页面
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。