第二篇:显示第一个地图

本篇教程将带你创建并显示第一个高德地图界面,理解地图组件的基本使用方法。

学习目标

  • 掌握MapViewComponent组件的使用
  • 理解地图生命周期管理
  • 学会获取AMap对象进行地图操作
  • 实现基本的地图显示

1. 核心概念

1.1 MapViewComponent

MapViewComponent 是高德地图提供的ArkUI组件,用于在页面中显示地图。

1.2 MapView与AMap

  • MapView: 地图视图对象,管理地图的生命周期
  • AMap: 地图控制对象,用于操作地图(缩放、移动、添加标记等)

1.3 生命周期流程

MapViewComponent创建 → MapViewManager回调 → MapView.onCreate() → getMapAsync() → 获取AMap对象

2. 创建地图页面

2.1 基础代码

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

import {
  AMap,
  MapView,
  MapViewComponent,
  MapViewManager,
  MapViewCreateCallback,
  CameraUpdateFactory,
  LatLng
} from '@amap/amap_lbs_map3d';
import { Constants } from '../common/Constants';

// 地图视图名称常量
const MAP_VIEW_NAME = 'BasicMapDemo';

@Entry
@Component
struct Demo01_BasicMap {
  // 地图视图对象
  private mapView: MapView | undefined = undefined;
  // 地图控制对象
  private aMap: AMap | undefined = undefined;
  
  // 页面状态
  @State isMapReady: boolean = false;
  @State mapInfo: string = '地图加载中...';

  /**
   * 地图视图创建回调
   */
  private mapViewCreateCallback: MapViewCreateCallback = 
    (mapview: MapView | undefined, mapViewName: string | undefined) => {
      // 检查是否是当前页面的地图
      if (!mapview || mapViewName !== MAP_VIEW_NAME) {
        return;
      }

      console.info('[BasicMap] MapView created');
      this.mapView = mapview;
      
      // 必须调用onCreate初始化地图
      this.mapView.onCreate();
      
      // 异步获取AMap对象
      this.mapView.getMapAsync((map: AMap) => {
        console.info('[BasicMap] AMap ready');
        this.aMap = map;
        this.isMapReady = true;
        
        // 设置地图初始位置
        this.initMapCamera();
        
        // 更新状态信息
        this.updateMapInfo();
      });
    };

  /**
   * 设置地图初始相机位置
   */
  private initMapCamera(): void {
    if (!this.aMap) return;
    
    // 创建目标位置(北京天安门)
    const center = new LatLng(
      Constants.DEFAULT_CENTER_LAT,
      Constants.DEFAULT_CENTER_LNG
    );
    
    // 移动相机到指定位置和缩放级别
    const cameraUpdate = CameraUpdateFactory.newLatLngZoom(
      center,
      Constants.DEFAULT_ZOOM
    );
    this.aMap.moveCamera(cameraUpdate);
  }

  /**
   * 更新地图信息显示
   */
  private updateMapInfo(): void {
    if (!this.aMap) return;
    
    const cameraPosition = this.aMap.getCameraPosition();
    if (cameraPosition) {
      const target = cameraPosition.target;
      this.mapInfo = `中心点: ${target.latitude.toFixed(6)}, ${target.longitude.toFixed(6)}\n缩放级别: ${cameraPosition.zoom.toFixed(1)}`;
    }
  }

  /**
   * 页面即将显示时注册回调
   */
  aboutToAppear(): void {
    console.info('[BasicMap] aboutToAppear');
    // 注册地图创建回调
    MapViewManager.getInstance()
      .registerMapViewCreatedCallback(this.mapViewCreateCallback);
  }

  /**
   * 页面即将销毁时清理资源
   */
  aboutToDisappear(): void {
    console.info('[BasicMap] aboutToDisappear');
    
    // 注销回调
    MapViewManager.getInstance()
      .unregisterMapViewCreatedCallback(this.mapViewCreateCallback);
    
    // 销毁地图
    if (this.mapView) {
      this.mapView.onDestroy();
      this.mapView = undefined;
      this.aMap = undefined;
    }
  }

  build() {
    Column() {
      // 标题栏
      Row() {
        Text('第一个地图')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
      .height(56)
      .padding({ left: 16, right: 16 })
      .backgroundColor('#4CAF50')

      // 地图容器
      Stack() {
        // 地图组件
        MapViewComponent({ mapViewName: MAP_VIEW_NAME })
          .width('100%')
          .height('100%')
        
        // 加载状态提示
        if (!this.isMapReady) {
          Column() {
            LoadingProgress()
              .width(50)
              .height(50)
            Text('地图加载中...')
              .fontSize(14)
              .fontColor('#666')
              .margin({ top: 10 })
          }
        }
        
        // 地图信息面板
        if (this.isMapReady) {
          Column() {
            Text(this.mapInfo)
              .fontSize(12)
              .fontColor('#333')
          }
          .padding(10)
          .backgroundColor('rgba(255,255,255,0.9)')
          .borderRadius(8)
          .position({ x: 10, y: 10 })
        }
      }
      .width('100%')
      .layoutWeight(1)

      // 底部操作栏
      Row() {
        Button('移动到北京')
          .onClick(() => this.moveToBeiJing())
          .margin({ right: 10 })
        
        Button('移动到上海')
          .onClick(() => this.moveToShanghai())
      }
      .width('100%')
      .height(60)
      .justifyContent(FlexAlign.Center)
      .backgroundColor('#f5f5f5')
    }
    .width('100%')
    .height('100%')
  }

  /**
   * 移动地图到北京
   */
  private moveToBeiJing(): void {
    if (!this.aMap) return;
    
    const beijing = new LatLng(39.909187, 116.397451);
    const cameraUpdate = CameraUpdateFactory.newLatLngZoom(beijing, 15);
    
    // 使用动画移动
    this.aMap.animateCamera(cameraUpdate, 1000);
    
    // 延迟更新信息
    setTimeout(() => this.updateMapInfo(), 1100);
  }

  /**
   * 移动地图到上海
   */
  private moveToShanghai(): void {
    if (!this.aMap) return;
    
    const shanghai = new LatLng(31.230416, 121.473701);
    const cameraUpdate = CameraUpdateFactory.newLatLngZoom(shanghai, 15);
    
    // 使用动画移动
    this.aMap.animateCamera(cameraUpdate, 1000);
    
    // 延迟更新信息
    setTimeout(() => this.updateMapInfo(), 1100);
  }
}

3. 配置路由

3.1 修改页面路由配置

entry/src/main/resources/base/profile/main_pages.json 中添加页面:

{
  "src": [
    "pages/Index",
    "pages/Demo01_BasicMap"
  ]
}

4. 关键代码解析

4.1 注册地图创建回调

MapViewManager.getInstance()
  .registerMapViewCreatedCallback(this.mapViewCreateCallback);

说明:

  • 必须在aboutToAppear中注册回调
  • 通过mapViewName区分不同的地图实例
  • 同一页面可以有多个地图,通过名称区分

4.2 地图生命周期管理

// 创建时初始化
this.mapView.onCreate();

// 销毁时清理
this.mapView.onDestroy();

说明:

  • onCreate()必须调用,否则地图无法正常显示
  • onDestroy()用于释放资源,防止内存泄漏

4.3 获取AMap对象

this.mapView.getMapAsync((map: AMap) => {
  this.aMap = map;
  // 在这里进行地图操作
});

说明:

  • getMapAsync是异步方法,地图准备好后回调
  • 所有地图操作都需要在获取AMap对象之后进行

4.4 相机控制

// 直接移动(无动画)
this.aMap.moveCamera(cameraUpdate);

// 动画移动
this.aMap.animateCamera(cameraUpdate, duration);

说明:

  • moveCamera立即移动,无过渡效果
  • animateCamera带动画效果,更平滑

5. CameraUpdateFactory 方法说明

方法 说明
newLatLng(latLng) 移动到指定位置,保持当前缩放级别
newLatLngZoom(latLng, zoom) 移动到指定位置和缩放级别
zoomIn() 放大一级
zoomOut() 缩小一级
zoomTo(zoom) 缩放到指定级别
newCameraPosition(position) 使用完整的相机参数

6. 运行效果

运行应用后,你将看到:

  1. 地图显示在屏幕中央
  2. 左上角显示当前地图中心点坐标和缩放级别
  3. 点击底部按钮可以平滑切换城市

7. 完整生命周期图示

┌─────────────────────────────────────────────────────┐
│                    页面生命周期                       │
├─────────────────────────────────────────────────────┤
│  aboutToAppear()                                    │
│       ↓                                             │
│  registerMapViewCreatedCallback()                   │
│       ↓                                             │
│  MapViewComponent 渲染                              │
│       ↓                                             │
│  mapViewCreateCallback 触发                         │
│       ↓                                             │
│  mapView.onCreate()                                 │
│       ↓                                             │
│  mapView.getMapAsync() → AMap 对象就绪              │
│       ↓                                             │
│  进行地图操作...                                     │
│       ↓                                             │
│  aboutToDisappear()                                 │
│       ↓                                             │
│  unregisterMapViewCreatedCallback()                 │
│       ↓                                             │
│  mapView.onDestroy()                                │
└─────────────────────────────────────────────────────┘

常见问题

Q1: 地图显示空白?

A: 检查以下几点:

  • API Key是否正确配置
  • 是否有网络权限
  • 是否调用了mapView.onCreate()

Q2: 多次进入页面崩溃?

A: 确保在aboutToDisappear中:

  • 注销了回调
  • 调用了mapView.onDestroy()

Q3: 地图显示灰色瓦片?

A: 可能是网络问题或API Key配额用尽,检查控制台日志。

本篇小结

本篇教程我们学习了:

  • ✅ MapViewComponent组件的基本使用
  • ✅ 地图创建回调机制
  • ✅ 地图生命周期管理
  • ✅ AMap对象的获取和使用
  • ✅ 相机位置控制

下一篇我们将学习如何切换地图类型和配置UI控件。
班级
https://developer.huawei.com/consumer/cn/training/classDetail/fd34ff9286174e848d34cde7f512ce22?type=1%3Fha_source%3Dhmosclass&ha_sourceId=89000248

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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐