[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第三篇:地图控制与UI设置

第三篇:地图控制与UI设置

本篇教程将学习如何切换地图类型、配置UI控件,以及监听地图事件。

学习目标

  • 掌握地图类型切换(标准、卫星、夜间等)
  • 配置地图UI控件(缩放按钮、指南针、比例尺)
  • 监听地图事件(点击、长按、相机变化)
  • 控制地图手势(缩放、旋转、倾斜)

1. 地图类型

高德地图支持多种地图类型:

类型 常量 说明
标准地图 MapType.MAP_TYPE_NORMAL 默认类型,显示道路和地标
卫星地图 MapType.MAP_TYPE_SATELLITE 显示卫星图像
夜间地图 MapType.MAP_TYPE_NIGHT 深色主题,适合夜间使用
导航地图 MapType.MAP_TYPE_NAVI 导航场景专用
导航夜间 MapType.MAP_TYPE_NAVI_NIGHT 导航夜间模式
公交地图 MapType.MAP_TYPE_BUS 突出显示公交线路

2. 完整代码示例

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

typescript 复制代码
import {
  AMap,
  MapView,
  MapViewComponent,
  MapViewManager,
  MapViewCreateCallback,
  MapType,
  CameraPosition,
  LatLng,
  OnCameraChangeListener,
  Poi,
  UiSettings
} from '@amap/amap_lbs_map3d';

const MAP_VIEW_NAME = 'MapControlDemo';

/**
 * 地图类型选项
 */
interface MapTypeOption {
  name: string;
  type: MapType;
}

@Entry
@Component
struct Demo02_MapControl {
  private mapView: MapView | undefined = undefined;
  private aMap: AMap | undefined = undefined;
  private uiSettings: UiSettings | undefined = undefined;
  
  @State isMapReady: boolean = false;
  @State currentMapType: string = '标准地图';
  @State cameraInfo: string = '';
  @State clickInfo: string = '点击地图查看坐标';
  
  // UI控件状态
  @State showZoomControls: boolean = true;
  @State showCompass: boolean = true;
  @State showScaleControls: boolean = true;
  @State enableZoomGesture: boolean = true;
  @State enableRotateGesture: boolean = true;
  @State enableTiltGesture: boolean = true;
  
  // 地图类型选项
  private mapTypes: MapTypeOption[] = [
    { name: '标准地图', type: MapType.MAP_TYPE_NORMAL },
    { name: '卫星地图', type: MapType.MAP_TYPE_SATELLITE },
    { name: '夜间地图', type: MapType.MAP_TYPE_NIGHT },
    { name: '导航地图', type: MapType.MAP_TYPE_NAVI },
    { name: '公交地图', type: MapType.MAP_TYPE_BUS }
  ];

  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.uiSettings = map.getUiSettings();
        this.isMapReady = true;
        
        // 设置事件监听
        this.setupEventListeners();
        
        // 初始化UI设置
        this.applyUiSettings();
      });
    };

  /**
   * 设置事件监听器
   */
  private setupEventListeners(): void {
    if (!this.aMap) return;
    
    // 1. 地图点击事件
    this.aMap.setOnMapClickListener((point: LatLng) => {
      console.info('[MapControl] Map clicked:', point.latitude, point.longitude);
      this.clickInfo = `点击: ${point.latitude.toFixed(6)}, ${point.longitude.toFixed(6)}`;
    });
    
    // 2. 地图长按事件
    this.aMap.setOnMapLongClickListener((point: LatLng) => {
      console.info('[MapControl] Map long clicked:', point.latitude, point.longitude);
      this.clickInfo = `长按: ${point.latitude.toFixed(6)}, ${point.longitude.toFixed(6)}`;
    });
    
    // 3. 相机变化事件
    this.aMap.setOnCameraChangeListener(new OnCameraChangeListener(
      // 相机移动中
      (position: CameraPosition) => {
        this.updateCameraInfo(position);
      },
      // 相机移动结束
      (position: CameraPosition) => {
        this.updateCameraInfo(position);
        console.info('[MapControl] Camera change finished');
      }
    ));
    
    // 4. POI点击事件
    this.aMap.addOnPOIClickListener((poi: Poi) => {
      const name = poi.getName();
      const poiId = poi.getPoiId();
      const coordinate = poi.getCoordinate();
      console.info('[MapControl] POI clicked:', name, poiId);
      
      if (coordinate) {
        this.clickInfo = `POI: ${name}\n${coordinate.latitude.toFixed(6)}, ${coordinate.longitude.toFixed(6)}`;
      }
    });
    
    // 5. 地图触摸事件
    this.aMap.setOnMapTouchListener((event: TouchEvent) => {
      // 可以获取触摸坐标进行自定义处理
      // console.info('[MapControl] Touch:', event.touches[0].x, event.touches[0].y);
    });
  }

  /**
   * 更新相机信息
   */
  private updateCameraInfo(position: CameraPosition): void {
    const target = position.target;
    this.cameraInfo = `经度: ${target.longitude.toFixed(4)}\n纬度: ${target.latitude.toFixed(4)}\n缩放: ${position.zoom.toFixed(1)}\n旋转: ${position.bearing.toFixed(0)}°\n倾斜: ${position.tilt.toFixed(0)}°`;
  }

  /**
   * 应用UI设置
   */
  private applyUiSettings(): void {
    if (!this.uiSettings) return;
    
    // 缩放控件
    this.uiSettings.setZoomControlsEnabled(this.showZoomControls);
    
    // 指南针
    this.uiSettings.setCompassEnabled(this.showCompass);
    
    // 比例尺
    this.uiSettings.setScaleControlsEnabled(this.showScaleControls);
    
    // 缩放手势
    this.uiSettings.setZoomGesturesEnabled(this.enableZoomGesture);
    
    // 旋转手势
    this.uiSettings.setRotateGesturesEnabled(this.enableRotateGesture);
    
    // 倾斜手势
    this.uiSettings.setTiltGesturesEnabled(this.enableTiltGesture);
  }

  /**
   * 切换地图类型
   */
  private setMapType(option: MapTypeOption): void {
    if (!this.aMap) return;
    
    this.aMap.setMapType(option.type);
    this.currentMapType = option.name;
    console.info('[MapControl] Map type changed to:', option.name);
  }

  aboutToAppear(): void {
    MapViewManager.getInstance()
      .registerMapViewCreatedCallback(this.mapViewCreateCallback);
  }

  aboutToDisappear(): void {
    MapViewManager.getInstance()
      .unregisterMapViewCreatedCallback(this.mapViewCreateCallback);
    
    if (this.mapView) {
      this.mapView.onDestroy();
      this.mapView = undefined;
      this.aMap = undefined;
    }
  }

  build() {
    Column() {
      // 标题栏
      Row() {
        Text('地图控制与UI设置')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
      }
      .width('100%')
      .height(50)
      .padding({ left: 16 })
      .backgroundColor('#2196F3')

      // 地图区域
      Stack() {
        MapViewComponent({ mapViewName: MAP_VIEW_NAME })
          .width('100%')
          .height('100%')
        
        // 相机信息面板
        if (this.isMapReady && this.cameraInfo) {
          Column() {
            Text('相机状态')
              .fontSize(12)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333')
            Text(this.cameraInfo)
              .fontSize(11)
              .fontColor('#666')
              .margin({ top: 4 })
          }
          .padding(8)
          .backgroundColor('rgba(255,255,255,0.9)')
          .borderRadius(8)
          .position({ x: 10, y: 10 })
        }
        
        // 点击信息
        if (this.isMapReady) {
          Text(this.clickInfo)
            .fontSize(12)
            .fontColor('#333')
            .padding(8)
            .backgroundColor('rgba(255,255,255,0.9)')
            .borderRadius(8)
            .position({ x: 10, y: 130 })
        }
      }
      .width('100%')
      .height('50%')

      // 控制面板
      Scroll() {
        Column() {
          // 地图类型选择
          Text('地图类型')
            .fontSize(14)
            .fontWeight(FontWeight.Bold)
            .width('100%')
            .margin({ bottom: 8 })
          
          Flex({ wrap: FlexWrap.Wrap }) {
            ForEach(this.mapTypes, (option: MapTypeOption) => {
              Button(option.name)
                .fontSize(12)
                .height(32)
                .backgroundColor(this.currentMapType === option.name ? '#2196F3' : '#e0e0e0')
                .fontColor(this.currentMapType === option.name ? Color.White : '#333')
                .margin({ right: 8, bottom: 8 })
                .onClick(() => this.setMapType(option))
            })
          }
          .margin({ bottom: 16 })

          // UI控件开关
          Text('UI控件')
            .fontSize(14)
            .fontWeight(FontWeight.Bold)
            .width('100%')
            .margin({ bottom: 8 })
          
          this.buildToggleRow('缩放按钮', this.showZoomControls, (value: boolean) => {
            this.showZoomControls = value;
            this.uiSettings?.setZoomControlsEnabled(value);
          })
          
          this.buildToggleRow('指南针', this.showCompass, (value: boolean) => {
            this.showCompass = value;
            this.uiSettings?.setCompassEnabled(value);
          })
          
          this.buildToggleRow('比例尺', this.showScaleControls, (value: boolean) => {
            this.showScaleControls = value;
            this.uiSettings?.setScaleControlsEnabled(value);
          })

          // 手势控制
          Text('手势控制')
            .fontSize(14)
            .fontWeight(FontWeight.Bold)
            .width('100%')
            .margin({ top: 16, bottom: 8 })
          
          this.buildToggleRow('缩放手势', this.enableZoomGesture, (value: boolean) => {
            this.enableZoomGesture = value;
            this.uiSettings?.setZoomGesturesEnabled(value);
          })
          
          this.buildToggleRow('旋转手势', this.enableRotateGesture, (value: boolean) => {
            this.enableRotateGesture = value;
            this.uiSettings?.setRotateGesturesEnabled(value);
          })
          
          this.buildToggleRow('倾斜手势', this.enableTiltGesture, (value: boolean) => {
            this.enableTiltGesture = value;
            this.uiSettings?.setTiltGesturesEnabled(value);
          })
        }
        .padding(16)
        .width('100%')
        .alignItems(HorizontalAlign.Start)
      }
      .layoutWeight(1)
      .backgroundColor('#fafafa')
    }
    .width('100%')
    .height('100%')
  }

  /**
   * 构建开关行
   */
  @Builder
  buildToggleRow(label: string, value: boolean, onChange: (value: boolean) => void) {
    Row() {
      Text(label)
        .fontSize(14)
        .fontColor('#333')
      Blank()
      Toggle({ type: ToggleType.Switch, isOn: value })
        .onChange(onChange)
    }
    .width('100%')
    .height(44)
    .padding({ left: 12, right: 12 })
    .backgroundColor(Color.White)
    .borderRadius(8)
    .margin({ bottom: 8 })
  }
}

3. UiSettings 完整方法列表

typescript 复制代码
interface UiSettings {
  // 缩放控件
  setZoomControlsEnabled(enabled: boolean): void;
  isZoomControlsEnabled(): boolean;
  
  // 指南针
  setCompassEnabled(enabled: boolean): void;
  isCompassEnabled(): boolean;
  
  // 比例尺
  setScaleControlsEnabled(enabled: boolean): void;
  isScaleControlsEnabled(): boolean;
  
  // 缩放手势
  setZoomGesturesEnabled(enabled: boolean): void;
  isZoomGesturesEnabled(): boolean;
  
  // 滑动手势
  setScrollGesturesEnabled(enabled: boolean): void;
  isScrollGesturesEnabled(): boolean;
  
  // 旋转手势
  setRotateGesturesEnabled(enabled: boolean): void;
  isRotateGesturesEnabled(): boolean;
  
  // 倾斜手势
  setTiltGesturesEnabled(enabled: boolean): void;
  isTiltGesturesEnabled(): boolean;
  
  // 所有手势
  setAllGesturesEnabled(enabled: boolean): void;
  
  // 缩放控件位置
  setZoomPosition(position: number): void;
  
  // Logo位置
  setLogoPosition(position: number): void;
}

4. 地图事件监听详解

4.1 点击事件

typescript 复制代码
// 普通点击
aMap.setOnMapClickListener((point: LatLng) => {
  console.log('点击坐标:', point.latitude, point.longitude);
});

// 长按
aMap.setOnMapLongClickListener((point: LatLng) => {
  console.log('长按坐标:', point.latitude, point.longitude);
});

// POI点击
aMap.addOnPOIClickListener((poi: Poi) => {
  console.log('POI名称:', poi.getName());
  console.log('POI ID:', poi.getPoiId());
});

4.2 相机变化事件

typescript 复制代码
aMap.setOnCameraChangeListener(new OnCameraChangeListener(
  // 移动中回调(频繁触发)
  (position: CameraPosition) => {
    console.log('移动中:', position.target);
  },
  // 移动结束回调
  (position: CameraPosition) => {
    console.log('移动结束:', position.target);
  }
));

4.3 CameraPosition 属性

typescript 复制代码
interface CameraPosition {
  target: LatLng;    // 中心点坐标
  zoom: number;      // 缩放级别 (3-20)
  bearing: number;   // 旋转角度 (0-360)
  tilt: number;      // 倾斜角度 (0-60)
}

5. 缩放控件位置配置

typescript 复制代码
import { AMapOptions } from '@amap/amap_lbs_map3d';

// 设置缩放控件位置
uiSettings.setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_CENTER);  // 右侧中间
uiSettings.setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_BUTTOM);  // 右下角

6. 实用技巧

6.1 禁止地图移动

typescript 复制代码
// 锁定地图,禁止所有手势
uiSettings.setAllGesturesEnabled(false);

6.2 只允许缩放

typescript 复制代码
uiSettings.setZoomGesturesEnabled(true);
uiSettings.setScrollGesturesEnabled(false);
uiSettings.setRotateGesturesEnabled(false);
uiSettings.setTiltGesturesEnabled(false);

6.3 重置地图方向

typescript 复制代码
// 重置为正北方向
const position = new CameraPosition(
  aMap.getCameraPosition().target,
  aMap.getCameraPosition().zoom,
  0,  // bearing = 0 表示正北
  0   // tilt = 0 表示垂直向下看
);
aMap.animateCamera(CameraUpdateFactory.newCameraPosition(position));

本篇小结

本篇教程我们学习了:

  • ✅ 6种地图类型及切换方法
  • ✅ UI控件的显示与隐藏
  • ✅ 手势控制配置
  • ✅ 地图事件监听(点击、长按、相机变化)
  • ✅ CameraPosition相机参数

下一篇我们将学习如何在地图上添加标记(Marker)。

班级

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

源码地址

https://gitcode.com/daleishen/gaodehmjiaocheng.git

相关推荐
●VON15 小时前
从单机应用到分布式调度:基于 HarmonyOS 构建车-空协同任务引擎
学习·华为·harmonyos·openharmony·开源鸿蒙
盐焗西兰花15 小时前
鸿蒙学习实战之路 - 避免冗余刷新最佳实践
学习·华为·harmonyos
zhujian8263718 小时前
十七、【鸿蒙 NEXT】如何实现lottie动画
华为·harmonyos·lottie
大雷神19 小时前
[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第十篇:综合实战案例
harmonyos
大雷神19 小时前
[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第六篇:POI搜索功能
harmonyos
盐焗西兰花21 小时前
鸿蒙学习实战之路 - 应用追踪实践最佳实践
学习·华为·harmonyos
大雷神21 小时前
[鸿蒙2025领航者闯关]HarmonyOS中开发高德地图第二篇:显示第一个地图
harmonyos
ujainu1 天前
Flutter与DevEco Studio协同开发:HarmonyOS应用实战指南
flutter·华为·harmonyos
赵财猫._.1 天前
【Flutter x 鸿蒙】第四篇:双向通信——Flutter调用鸿蒙原生能力
flutter·华为·harmonyos