绵阳市网站建设_网站建设公司_前后端分离_seo优化
2026/1/3 9:52:44 网站建设 项目流程

[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第五篇:定位蓝点效果

2026-01-03 09:49  tlnshuju  阅读(0)  评论(0)    收藏  举报

第五篇:定位蓝点功能

本篇教程将学习如何在地图上显示用户当前位置(定位蓝点),包括权限申请、定位样式自定义等。

学习目标

1. 定位权限配置

1.1 module.json5 权限声明

{"module": {"requestPermissions": [{"name": "ohos.permission.LOCATION","reason": "$string:permission_location_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.APPROXIMATELY_LOCATION","reason": "$string:permission_location_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]}
}

1.2 权限说明

权限说明
ohos.permission.LOCATION精确定位权限
ohos.permission.APPROXIMATELY_LOCATION模糊定位权限

注意: 申请精确定位时必须同时申请模糊定位权限。

2. 定位模式说明

MyLocationStyle 提供了多种定位模式:

模式常量说明
只展示LOCATION_TYPE_SHOW只显示位置,不移动地图
定位一次LOCATION_TYPE_LOCATE定位一次并移动到该位置
跟随LOCATION_TYPE_FOLLOW持续跟随位置移动
地图旋转LOCATION_TYPE_MAP_ROTATE地图随手机方向旋转
定位点旋转LOCATION_TYPE_LOCATION_ROTATE定位点随方向旋转
跟随不移中心LOCATION_TYPE_FOLLOW_NO_CENTER跟随但不移动地图中心
地图旋转不移中心LOCATION_TYPE_MAP_ROTATE_NO_CENTER地图旋转但不移中心
定位点旋转不移中心LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER定位点旋转但不移中心

3. 完整代码示例

创建文件 entry/src/main/ets/pages/Demo04_Location.ets

import {
AMap,
MapView,
MapViewComponent,
MapViewManager,
MapViewCreateCallback,
CameraUpdateFactory,
LatLng,
MyLocationStyle,
BitmapDescriptorFactory,
OnLocationChangedListener
} from '@amap/amap_lbs_map3d';
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { geoLocationManager } from '@kit.LocationKit';
const MAP_VIEW_NAME = 'LocationDemo';
// 获取应用上下文
let globalContext: Context;
/**
* 定位模式选项
*/
interface LocationModeOption {
name: string;
mode: number;
}
@Entry
@Component
struct Demo04_Location {
private mapView: MapView | undefined = undefined;
private aMap: AMap | undefined = undefined;
private locationStyle: MyLocationStyle = new MyLocationStyle();
private locationIntervalId: number = 0;
@State isMapReady: boolean = false;
@State hasLocationPermission: boolean = false;
@State isLocationEnabled: boolean = false;
@State currentMode: string = '只展示';
@State locationInfo: string = '等待定位...';
@State permissionStatus: string = '检查权限中...';
// 定位模式选项
private locationModes: LocationModeOption[] = [
{ name: '只展示', mode: MyLocationStyle.LOCATION_TYPE_SHOW },
{ name: '定位一次', mode: MyLocationStyle.LOCATION_TYPE_LOCATE },
{ name: '跟随', mode: MyLocationStyle.LOCATION_TYPE_FOLLOW },
{ name: '地图旋转', mode: MyLocationStyle.LOCATION_TYPE_MAP_ROTATE },
{ name: '定位点旋转', mode: MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE }
];
private mapViewCreateCallback: MapViewCreateCallback =
(mapview: MapView | undefined, mapViewName: string | undefined) => {
if (!mapview || mapViewName !== MAP_VIEW_NAME) return;
this.mapView = mapview;
this.mapView.onCreate();
this.mapView.getMapAsync(async (map: AMap) => {
this.aMap = map;
this.isMapReady = true;
// 启用缩放控件
map.getUiSettings()?.setZoomControlsEnabled(true);
// 检查权限并配置定位
await this.checkAndRequestPermission();
});
};
/**
* 检查并请求定位权限
*/
private async checkAndRequestPermission(): Promise<void> {try {const permission: Permissions = 'ohos.permission.LOCATION';const grantStatus = await this.checkAccessToken(permission);if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {this.hasLocationPermission = true;this.permissionStatus = '✅ 定位权限已授予';// 配置定位await this.configureLocation();} else {this.permissionStatus = '⏳ 正在请求权限...';// 请求权限await this.requestPermissions();}} catch (error) {console.error('[Location] Permission check failed:', error);this.permissionStatus = '❌ 权限检查失败';}}/*** 检查权限状态*/private async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {const atManager = abilityAccessCtrl.createAtManager();let grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;try {const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);const tokenId = bundleInfo.appInfo.accessTokenId;grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (error) {console.error('[Location] Check token failed:', error);}return grantStatus;}/*** 请求权限*/private async requestPermissions(): Promise<void> {const permissions: Permissions[] = ['ohos.permission.APPROXIMATELY_LOCATION','ohos.permission.LOCATION'];try {const context = getContext(this) as common.UIAbilityContext;const atManager = abilityAccessCtrl.createAtManager();const result = await atManager.requestPermissionsFromUser(context, permissions);const allGranted = result.authResults.every(status => status === 0);if (allGranted) {this.hasLocationPermission = true;this.permissionStatus = '✅ 定位权限已授予';await this.configureLocation();} else {this.hasLocationPermission = false;this.permissionStatus = '❌ 用户拒绝了定位权限';}} catch (error) {console.error('[Location] Request permission failed:', error);this.permissionStatus = '❌ 权限请求失败';}}/*** 配置定位蓝点*/private async configureLocation(): Promise<void> {if (!this.aMap) return;try {// 设置定位样式this.locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);// 自定义定位图标(可选)try {const icon = await BitmapDescriptorFactory.fromRawfilePath(globalContext,'location_icon.png');if (icon) {this.locationStyle.myLocationIcon(icon);}} catch (e) {console.info('[Location] Using default location icon');}// 设置精度圈样式this.locationStyle.strokeColor(0x800000FF);  // 边框颜色(带透明度的蓝色)this.locationStyle.strokeWidth(2);            // 边框宽度this.locationStyle.radiusFillColor(0x200000FF); // 填充颜色// 应用样式this.aMap.setMyLocationStyle(this.locationStyle);// 设置定位数据源this.aMap.setLocationSource(this);// 启用定位图层this.aMap.setMyLocationEnabled(true);this.isLocationEnabled = true;this.locationInfo = '定位已启用,等待位置更新...';console.info('[Location] Location configured successfully');} catch (error) {console.error('[Location] Configure location failed:', error);this.locationInfo = '定位配置失败';}}/*** LocationSource接口实现 - 激活定位*/activate(listener: OnLocationChangedListener): void {console.info('[Location] activate called');// 使用系统定位获取位置this.startSystemLocation(listener);}/*** LocationSource接口实现 - 停用定位*/deactivate(): void {console.info('[Location] deactivate called');if (this.locationIntervalId > 0) {clearInterval(this.locationIntervalId);this.locationIntervalId = 0;}}/*** 启动系统定位*/private startSystemLocation(listener: OnLocationChangedListener): void {// 定位请求配置const requestInfo: geoLocationManager.CurrentLocationRequest = {priority: geoLocationManager.LocationRequestPriority.FIRST_FIX,scenario: geoLocationManager.LocationRequestScenario.UNSET,maxAccuracy: 100};// 获取当前位置geoLocationManager.getCurrentLocation(requestInfo).then((location: geoLocationManager.Location) => {console.info('[Location] Got location:', location.latitude, location.longitude);// 转换为高德定位格式const amapLocation: geoLocationManager.Location = {latitude: location.latitude,longitude: location.longitude,altitude: location.altitude,accuracy: location.accuracy,speed: location.speed,direction: location.direction,timeStamp: location.timeStamp,timeSinceBoot: location.timeSinceBoot,altitudeAccuracy: location.altitudeAccuracy || 0,speedAccuracy: location.speedAccuracy || 0,directionAccuracy: location.directionAccuracy || 0,uncertaintyOfTimeSinceBoot: location.uncertaintyOfTimeSinceBoot || 0,sourceType: location.sourceType || 1};// 更新位置到地图listener.onLocationChanged(amapLocation);// 更新UI显示this.locationInfo = `经度: ${location.longitude.toFixed(6)}\n纬度: ${location.latitude.toFixed(6)}\n精度: ${location.accuracy?.toFixed(0) || '未知'}`;// 移动地图到当前位置if (this.aMap) {const latLng = new LatLng(location.latitude, location.longitude);this.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));}}).catch((error: BusinessError) => {console.error('[Location] Get location failed:', error.message);this.locationInfo = '获取位置失败: ' + error.message;// 使用模拟位置(开发测试用)this.useSimulatedLocation(listener);});// 设置定时更新(可选)if (this.locationIntervalId === 0) {this.locationIntervalId = setInterval(() => {geoLocationManager.getCurrentLocation(requestInfo).then((location) => {const amapLocation: geoLocationManager.Location = {latitude: location.latitude,longitude: location.longitude,altitude: location.altitude,accuracy: location.accuracy,speed: location.speed,direction: location.direction,timeStamp: location.timeStamp,timeSinceBoot: location.timeSinceBoot,altitudeAccuracy: location.altitudeAccuracy || 0,speedAccuracy: location.speedAccuracy || 0,directionAccuracy: location.directionAccuracy || 0,uncertaintyOfTimeSinceBoot: location.uncertaintyOfTimeSinceBoot || 0,sourceType: location.sourceType || 1};listener.onLocationChanged(amapLocation);this.locationInfo = `经度: ${location.longitude.toFixed(6)}\n纬度: ${location.latitude.toFixed(6)}\n精度: ${location.accuracy?.toFixed(0) || '未知'}`;}).catch(() => {});}, 5000);}}/*** 使用模拟位置(开发测试用)*/private useSimulatedLocation(listener: OnLocationChangedListener): void {// 模拟北京位置const simulatedLocation: geoLocationManager.Location = {latitude: 39.909187,longitude: 116.397451,altitude: 50,accuracy: 100,speed: 0,direction: 0,timeStamp: Date.now(),timeSinceBoot: 0,altitudeAccuracy: 0,speedAccuracy: 0,directionAccuracy: 0,uncertaintyOfTimeSinceBoot: 0,sourceType: 1};listener.onLocationChanged(simulatedLocation);this.locationInfo = `[模拟] 经度: ${simulatedLocation.longitude.toFixed(6)}\n纬度: ${simulatedLocation.latitude.toFixed(6)}`;if (this.aMap) {const latLng = new LatLng(simulatedLocation.latitude, simulatedLocation.longitude);this.aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));}}/*** 切换定位模式*/private setLocationMode(option: LocationModeOption): void {if (!this.aMap) return;this.locationStyle.myLocationType(option.mode);this.aMap.setMyLocationStyle(this.locationStyle);this.currentMode = option.name;console.info('[Location] Mode changed to:', option.name);}/*** 切换定位开关*/private toggleLocation(): void {if (!this.aMap) return;this.isLocationEnabled = !this.isLocationEnabled;this.aMap.setMyLocationEnabled(this.isLocationEnabled);if (!this.isLocationEnabled) {this.locationInfo = '定位已关闭';}}aboutToAppear(): void {globalContext = getContext(this).getApplicationContext();MapViewManager.getInstance().registerMapViewCreatedCallback(this.mapViewCreateCallback);}aboutToDisappear(): void {// 停止定位更新if (this.locationIntervalId > 0) {clearInterval(this.locationIntervalId);this.locationIntervalId = 0;}// 关闭定位if (this.aMap) {this.aMap.setMyLocationEnabled(false);}MapViewManager.getInstance().unregisterMapViewCreatedCallback(this.mapViewCreateCallback);if (this.mapView) {this.mapView.onDestroy();this.mapView = undefined;this.aMap = undefined;}}build() {Column() {// 标题栏Row() {Text('定位蓝点功能').fontSize(18).fontWeight(FontWeight.Bold).fontColor(Color.White)}.width('100%').height(50).padding({ left: 16 }).backgroundColor('#03A9F4')// 地图区域Stack() {MapViewComponent({ mapViewName: MAP_VIEW_NAME }).width('100%').height('100%')// 状态信息面板Column() {Text('定位状态').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#333')Text(this.permissionStatus).fontSize(11).fontColor('#666').margin({ top: 4 })Text(this.locationInfo).fontSize(11).fontColor('#666').margin({ top: 4 })Text(`当前模式: ${this.currentMode}`).fontSize(11).fontColor('#2196F3').margin({ top: 4 })}.padding(10).backgroundColor('rgba(255,255,255,0.95)').borderRadius(8).position({ x: 10, y: 10 }).alignItems(HorizontalAlign.Start)}.width('100%').layoutWeight(1)// 控制面板Column() {// 定位开关Row() {Text('定位蓝点').fontSize(14).fontColor('#333')Blank()Toggle({ type: ToggleType.Switch, isOn: this.isLocationEnabled }).enabled(this.hasLocationPermission).onChange((isOn: boolean) => {this.isLocationEnabled = isOn;this.aMap?.setMyLocationEnabled(isOn);})}.width('100%').height(44).padding({ left: 12, right: 12 }).backgroundColor(Color.White).borderRadius(8).margin({ bottom: 8 })// 定位模式选择Text('定位模式').fontSize(14).fontWeight(FontWeight.Bold).width('100%').margin({ bottom: 8 })Flex({ wrap: FlexWrap.Wrap }) {ForEach(this.locationModes, (option: LocationModeOption) => {Button(option.name).fontSize(11).height(32).backgroundColor(this.currentMode === option.name ? '#03A9F4' : '#e0e0e0').fontColor(this.currentMode === option.name ? Color.White : '#333').margin({ right: 6, bottom: 6 }).enabled(this.hasLocationPermission && this.isLocationEnabled).onClick(() => this.setLocationMode(option))})}// 重新定位按钮Button('重新定位').width('100%').height(40).margin({ top: 8 }).enabled(this.hasLocationPermission).onClick(() => this.configureLocation())}.padding(12).backgroundColor('#f5f5f5')}.width('100%').height('100%')}}

4. MyLocationStyle 完整API

class MyLocationStyle {
// 设置定位模式
myLocationType(type: number): MyLocationStyle;
// 设置定位图标
myLocationIcon(icon: BitmapDescriptor): MyLocationStyle;
// 设置定位间隔(毫秒)
interval(interval: number): MyLocationStyle;
// 精度圈边框颜色
strokeColor(color: number): MyLocationStyle;
// 精度圈边框宽度
strokeWidth(width: number): MyLocationStyle;
// 精度圈填充颜色
radiusFillColor(color: number): MyLocationStyle;
// 是否显示精度圈
showMyLocation(show: boolean): MyLocationStyle;
}

5. 颜色值说明

高德地图使用ARGB格式的颜色值:

// 格式: 0xAARRGGBB
// AA: 透明度 (00=完全透明, FF=完全不透明)
// RR: 红色
// GG: 绿色
// BB: 蓝色
// 示例
0x800000FF  // 半透明蓝色
0x200000FF  // 较透明的蓝色
0xFF00FF00  // 不透明绿色

6. 实用技巧

6.1 判断定位服务是否可用

import { geoLocationManager } from '@kit.LocationKit';
const isEnabled = geoLocationManager.isLocationEnabled();
if (!isEnabled) {
// 提示用户开启定位服务
}

6.2 引导用户开启权限

import { common } from '@kit.AbilityKit';
// 跳转到应用设置页面
const context = getContext(this) as common.UIAbilityContext;
const want: common.Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
pushParams: context.abilityInfo.bundleName
}
};
context.startAbility(want);

本篇小结

本篇教程我们学习了:

  • ✅ 定位权限的申请和检查
  • ✅ 定位蓝点的显示与配置
  • ✅ 多种定位模式的切换
  • ✅ 自定义定位蓝点样式
  • ✅ LocationSource接口实现

下一篇我们将学习POI搜索功能。

班级
https://developer.huawei.com/consumer/cn/training/classDetail/fd34ff9286174e848d34cde7f512ce22?type=1%3Fha_source%3Dhmosclass&ha_sourceId=89000248

源码地址
https://gitcode.com/daleishen/gaodehmjiaocheng.git

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询