[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第七篇:地理编码与逆地理编码
本篇教程将学习地理编码(地址转坐标)和逆地理编码(坐标转地址)功能。
·
第七篇:地理编码与逆地理编码
本篇教程将学习地理编码(地址转坐标)和逆地理编码(坐标转地址)功能。
学习目标
- 理解地理编码的概念
- 实现地址到坐标的转换
- 实现坐标到地址的转换
- 结合地图点击获取地址信息
1. 核心概念
| 名称 | 说明 | 示例 |
|---|---|---|
| 地理编码 | 将结构化地址转换为经纬度坐标 | “北京市朝阳区望京SOHO” → (39.99, 116.48) |
| 逆地理编码 | 将经纬度坐标转换为结构化地址 | (39.99, 116.48) → “北京市朝阳区望京街道…” |
2. 核心类说明
| 类名 | 说明 |
|---|---|
GeocodeSearch |
地理编码搜索类 |
GeocodeQuery |
地理编码查询条件 |
GeocodeResult |
地理编码结果 |
GeocodeAddress |
地理编码地址信息 |
ReGeocodeQuery |
逆地理编码查询条件 |
ReGeocodeResult |
逆地理编码结果 |
ReGeocodeAddress |
逆地理编码地址信息 |
3. 完整代码示例
创建文件 entry/src/main/ets/pages/Demo06_Geocode.ets:
import {
AMap,
MapView,
MapViewComponent,
MapViewManager,
MapViewCreateCallback,
CameraUpdateFactory,
LatLng,
Marker,
MarkerOptions,
BitmapDescriptorFactory
} from '@amap/amap_lbs_map3d';
import {
GeocodeSearch,
GeocodeQuery,
GeocodeResult,
GeocodeAddress,
ReGeocodeQuery,
ReGeocodeResult,
OnGeocodeSearchListener,
AMapException,
LatLonPoint
} from '@amap/amap_lbs_search';
import { inputMethod } from '@kit.IMEKit';
const MAP_VIEW_NAME = 'GeocodeDemo';
@Entry
@Component
struct Demo06_Geocode {
private mapView: MapView | undefined = undefined;
private aMap: AMap | undefined = undefined;
private geocodeSearch: GeocodeSearch | undefined = undefined;
private resultMarker: Marker | undefined = undefined;
@State isMapReady: boolean = false;
@State address: string = '北京市朝阳区望京SOHO';
@State city: string = '北京';
@State isSearching: boolean = false;
@State resultInfo: string = '';
@State clickedAddress: string = '点击地图获取地址';
/**
* 地理编码回调
*/
private geocodeListener: OnGeocodeSearchListener = {
// 地理编码回调(地址→坐标)
onGeocodeSearched: (result: GeocodeResult | undefined, errorCode: number) => {
this.isSearching = false;
if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
if (result) {
const addressList = result.getGeocodeAddressList();
if (addressList && addressList.length > 0) {
const address = addressList[0] as GeocodeAddress;
const point = address.getLatLonPoint();
if (point) {
const lat = point.getLatitude();
const lng = point.getLongitude();
this.resultInfo = `地理编码结果:\n地址: ${address.getFormatAddress() || this.address}\n坐标: ${lat.toFixed(6)}, ${lng.toFixed(6)}\n级别: ${address.getLevel() || '未知'}`;
// 移动地图并添加标记
this.showResultOnMap(lat, lng, address.getFormatAddress() || this.address);
}
} else {
this.resultInfo = '未找到该地址的坐标信息';
}
}
} else {
this.resultInfo = `地理编码失败: 错误码 ${errorCode}`;
console.error('[Geocode] Search failed:', errorCode);
}
},
// 逆地理编码回调(坐标→地址)
onReGeocodeSearched: (result: ReGeocodeResult | undefined, errorCode: number) => {
this.isSearching = false;
if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
if (result) {
const reGeocodeAddress = result.getReGeocodeAddress();
if (reGeocodeAddress) {
const formatAddress = reGeocodeAddress.getFormatAddress() || '';
const province = reGeocodeAddress.getProvince() || '';
const city = reGeocodeAddress.getCity() || '';
const district = reGeocodeAddress.getDistrict() || '';
const township = reGeocodeAddress.getTownship() || '';
const neighborhood = reGeocodeAddress.getNeighborhood() || '';
const building = reGeocodeAddress.getBuilding() || '';
this.clickedAddress = formatAddress;
this.resultInfo = `逆地理编码结果:\n完整地址: ${formatAddress}\n省份: ${province}\n城市: ${city}\n区县: ${district}\n街道: ${township}\n社区: ${neighborhood}\n建筑: ${building}`;
// 获取POI信息
const pois = reGeocodeAddress.getPois();
if (pois && pois.length > 0) {
const nearestPoi = pois[0];
this.resultInfo += `\n\n最近POI: ${nearestPoi.getTitle()}\n距离: ${nearestPoi.getDistance()}米`;
}
}
}
} else {
this.resultInfo = `逆地理编码失败: 错误码 ${errorCode}`;
console.error('[ReGeocode] Search failed:', errorCode);
}
}
};
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((map: AMap) => {
this.aMap = map;
this.isMapReady = true;
// 移动到北京
const beijing = new LatLng(39.909187, 116.397451);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(beijing, 13));
// 启用控件
map.getUiSettings()?.setZoomControlsEnabled(true);
// 地图点击事件 - 执行逆地理编码
map.setOnMapClickListener((point: LatLng) => {
console.info('[Geocode] Map clicked:', point.latitude, point.longitude);
this.doReGeocode(point.latitude, point.longitude);
});
// 地图长按事件 - 添加标记
map.setOnMapLongClickListener((point: LatLng) => {
this.showResultOnMap(point.latitude, point.longitude, '长按标记');
});
});
};
/**
* 执行地理编码(地址→坐标)
*/
private doGeocode(): void {
if (!this.geocodeSearch || !this.address.trim()) {
this.resultInfo = '请输入地址';
return;
}
inputMethod.getController().stopInputSession();
this.isSearching = true;
this.resultInfo = '正在查询...';
// 创建地理编码查询
const query = new GeocodeQuery(this.address, this.city);
// 执行异步查询
this.geocodeSearch.getFromLocationNameAsyn(query);
console.info('[Geocode] Searching:', this.address, 'in', this.city);
}
/**
* 执行逆地理编码(坐标→地址)
*/
private doReGeocode(lat: number, lng: number): void {
if (!this.geocodeSearch) return;
this.isSearching = true;
this.clickedAddress = '正在获取地址...';
// 添加/更新标记
this.showResultOnMap(lat, lng, '');
// 创建逆地理编码查询
const point = new LatLonPoint(lat, lng);
const query = new ReGeocodeQuery(
point,
200, // 搜索半径(米)
'base' // 返回类型:base-基础信息,all-详细信息
);
// 执行异步查询
this.geocodeSearch.getFromLocationAsyn(query);
console.info('[ReGeocode] Searching:', lat, lng);
}
/**
* 在地图上显示结果
*/
private showResultOnMap(lat: number, lng: number, title: string): void {
if (!this.aMap) return;
// 移除之前的标记
if (this.resultMarker) {
this.resultMarker.remove();
}
// 添加新标记
const options = new MarkerOptions();
options.setPosition(new LatLng(lat, lng));
options.setTitle(title || '查询结果');
options.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
options.setAnchor(0.5, 1.0);
this.resultMarker = this.aMap.addMarker(options);
// 移动地图
this.aMap.animateCamera(
CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 16),
500
);
}
/**
* 使用预设地址
*/
private usePresetAddress(preset: string): void {
this.address = preset;
this.doGeocode();
}
aboutToAppear(): void {
MapViewManager.getInstance()
.registerMapViewCreatedCallback(this.mapViewCreateCallback);
// 初始化地理编码搜索
const context = getContext(this);
this.geocodeSearch = new GeocodeSearch(context);
this.geocodeSearch.setOnGeocodeSearchListener(this.geocodeListener);
}
aboutToDisappear(): void {
if (this.resultMarker) {
this.resultMarker.remove();
}
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('#009688')
// 搜索栏
Column() {
// 地址输入
Row() {
TextInput({ text: this.address, placeholder: '输入地址' })
.layoutWeight(1)
.height(40)
.onChange((value: string) => { this.address = value; })
TextInput({ text: this.city, placeholder: '城市' })
.width(70)
.height(40)
.margin({ left: 8 })
.onChange((value: string) => { this.city = value; })
Button('查询')
.height(40)
.margin({ left: 8 })
.enabled(!this.isSearching)
.onClick(() => this.doGeocode())
}
.width('100%')
// 预设地址快捷按钮
Text('快捷地址:')
.fontSize(12)
.fontColor('#666')
.width('100%')
.margin({ top: 8 })
Flex({ wrap: FlexWrap.Wrap }) {
Button('天安门')
.fontSize(11)
.height(28)
.margin({ right: 6, top: 4 })
.backgroundColor('#e0e0e0')
.fontColor('#333')
.onClick(() => this.usePresetAddress('北京市天安门'))
Button('东方明珠')
.fontSize(11)
.height(28)
.margin({ right: 6, top: 4 })
.backgroundColor('#e0e0e0')
.fontColor('#333')
.onClick(() => {
this.city = '上海';
this.usePresetAddress('上海市东方明珠');
})
Button('西湖')
.fontSize(11)
.height(28)
.margin({ right: 6, top: 4 })
.backgroundColor('#e0e0e0')
.fontColor('#333')
.onClick(() => {
this.city = '杭州';
this.usePresetAddress('杭州市西湖');
})
}
}
.padding(12)
.backgroundColor('#f5f5f5')
// 地图区域
Stack() {
MapViewComponent({ mapViewName: MAP_VIEW_NAME })
.width('100%')
.height('100%')
// 点击提示
Column() {
Text('点击地图获取地址')
.fontSize(11)
.fontColor('#fff')
Text(this.clickedAddress)
.fontSize(10)
.fontColor('#fff')
.margin({ top: 4 })
.maxLines(2)
}
.padding(8)
.backgroundColor('rgba(0,0,0,0.7)')
.borderRadius(8)
.position({ x: 10, y: 10 })
}
.width('100%')
.layoutWeight(1)
// 结果显示区
if (this.resultInfo) {
Scroll() {
Text(this.resultInfo)
.fontSize(12)
.fontColor('#333')
.width('100%')
}
.height(120)
.padding(12)
.backgroundColor(Color.White)
}
}
.width('100%')
.height('100%')
}
}
4. 地理编码详解
4.1 GeocodeQuery 参数
// 创建查询
const query = new GeocodeQuery(
address, // 地址字符串
city // 城市(可为空)
);
// 城市参数说明:
// - 可传入城市名称,如"北京"
// - 可传入城市编码,如"010"
// - 可传入adcode,如"110000"
// - 传空字符串则全国搜索
4.2 GeocodeAddress 结果
interface GeocodeAddress {
getFormatAddress(): string; // 格式化地址
getLatLonPoint(): LatLonPoint; // 坐标
getProvince(): string; // 省份
getCity(): string; // 城市
getDistrict(): string; // 区县
getAdcode(): string; // 区域编码
getLevel(): string; // 匹配级别
getTownship(): string; // 街道/乡镇
}
5. 逆地理编码详解
5.1 ReGeocodeQuery 参数
const query = new ReGeocodeQuery(
point, // LatLonPoint 坐标点
radius, // 搜索半径(米),取值范围0-3000
type // 返回类型:"base"基础信息,"all"详细信息
);
5.2 ReGeocodeAddress 结果
interface ReGeocodeAddress {
getFormatAddress(): string; // 格式化地址
getProvince(): string; // 省
getCity(): string; // 市
getDistrict(): string; // 区/县
getTownship(): string; // 乡镇/街道
getNeighborhood(): string; // 社区
getBuilding(): string; // 建筑物
getAdCode(): string; // 区域编码
getCityCode(): string; // 城市编码
getCountry(): string; // 国家
// 获取POI列表(type为"all"时有效)
getPois(): PoiItem[];
// 获取道路信息
getRoads(): Road[];
// 获取交叉口信息
getCrossroads(): Crossroad[];
}
6. 同步与异步调用
6.1 异步调用(推荐)
// 地理编码
geocodeSearch.getFromLocationNameAsyn(query);
// 逆地理编码
geocodeSearch.getFromLocationAsyn(query);
// 结果通过OnGeocodeSearchListener回调返回
6.2 同步调用
// 地理编码(会阻塞线程)
const result = await geocodeSearch.getFromLocationName(query);
// 逆地理编码
const result = await geocodeSearch.getFromLocation(query);
7. 匹配级别说明
| 级别 | 说明 |
|---|---|
| 国家 | 匹配到国家级别 |
| 省 | 匹配到省级别 |
| 市 | 匹配到市级别 |
| 区县 | 匹配到区县级别 |
| 开发区 | 匹配到开发区级别 |
| 乡镇 | 匹配到乡镇级别 |
| 村庄 | 匹配到村庄级别 |
| 道路 | 匹配到道路级别 |
| 门牌号 | 匹配到门牌号级别 |
| POI | 匹配到兴趣点级别 |
8. 实用技巧
8.1 批量地理编码
async function batchGeocode(addresses: string[], city: string): Promise<LatLonPoint[]> {
const results: LatLonPoint[] = [];
for (const addr of addresses) {
const query = new GeocodeQuery(addr, city);
const result = await geocodeSearch.getFromLocationName(query);
if (result) {
const list = result.getGeocodeAddressList();
if (list && list.length > 0) {
const point = list[0].getLatLonPoint();
if (point) {
results.push(point);
}
}
}
}
return results;
}
8.2 结合地图操作
// 地图点击时自动获取地址
aMap.setOnMapClickListener((point: LatLng) => {
const latLonPoint = new LatLonPoint(point.latitude, point.longitude);
const query = new ReGeocodeQuery(latLonPoint, 200, 'base');
geocodeSearch.getFromLocationAsyn(query);
});
本篇小结
本篇教程我们学习了:
- ✅ 地理编码的概念和使用场景
- ✅ 地址转坐标的实现
- ✅ 坐标转地址的实现
- ✅ 结合地图点击获取地址
- ✅ 解析返回的详细地址信息
下一篇我们将学习路线规划功能。
班级
https://developer.huawei.com/consumer/cn/training/classDetail/fd34ff9286174e848d34cde7f512ce22?type=1%3Fha_source%3Dhmosclass&ha_sourceId=89000248
源码地址
https://gitcode.com/daleishen/gaodehmjiaocheng.git
更多推荐
所有评论(0)