HarmonyOS鸿蒙Next地图多信息窗实现

HarmonyOS鸿蒙Next地图多信息窗实现 目前HarmonyOSSDK中地图服务提供的信息窗能力只针对单marker,针对多marker场景目前没有规划,依赖地图服务的现有能力,可以不依赖地图服务的信息窗能力实现多信息窗。

export class InfoWindowOptions {
  positionX:number = 0;
  positionY:number = 0;
}

import { map, mapCommon, MapComponent } from '@kit.MapKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
import { InfoWindowOptions } from './dto/InfoWindowOptions';
import { image } from '@kit.ImageKit';

@Entry
@Component
struct BasicMapDemo {
  private TAG = "OHMapSDK_BasicMapDemo";
  @State resultText: string = "result";
  private mapOptions?: mapCommon.MapOptions;
  private callback?: AsyncCallback<map.MapComponentController>;
  private mapController?: map.MapComponentController;
  @State infoWindowOptions: InfoWindowOptions = new InfoWindowOptions();
  @State show: boolean = false;
  private infoAnchorU: number = 0.5; // 信息窗X轴的偏移
  private infoAnchorV: number = 0; // 信息窗Y轴的偏移

  aboutToAppear(): void {
    let target: mapCommon.LatLng = {
      latitude: 31.984410259206815,
      longitude: 118.76625379397866
    }

    let cameraPosition: mapCommon.CameraPosition = {
      target: target,
      zoom: 15
    }
    this.mapOptions = {
      position: cameraPosition
    }

    this.callback = async (err, mapController) => {
      if (!err) {
        this.mapController = mapController;
        try {
          // 获取图片资源并转成 PixelMap
          let mContext = getContext();
          const fileData: Uint8Array = await mContext?.resourceManager?.getMediaContent($r('app.media.icon'));
          let imageSource: image.ImageSource =
            image.createImageSource(fileData.buffer.slice(0, fileData.buffer.byteLength));
          let pixelMap: PixelMap = await imageSource.createPixelMap();

          let markerOptions: mapCommon.MarkerOptions = {
            position: {
              latitude: 31.984410259206815,
              longitude: 118.76625379397866
            },
            icon: pixelMap
          }
          const imageInfo: image.ImageInfo = await pixelMap.getImageInfo();
          let marker = await this.mapController.addMarker(markerOptions);
          let point: mapCommon.MapPoint = this.mapController.getProjection().toScreenLocation(marker.getPosition());
          this.infoWindowOptions.positionX = point.positionX - imageInfo.size.width * (0.5 - this.infoAnchorU);
          this.infoWindowOptions.positionY = point.positionY - imageInfo.size.height * (1 - this.infoAnchorV);
          this.show = true;
          this.mapController.on('cameraMove', () => {
            if (this.mapController) {
              let point: mapCommon.MapPoint = this.mapController.getProjection().toScreenLocation(marker.getPosition());
              this.infoWindowOptions.positionX = point.positionX - imageInfo.size.width * (0.5 - this.infoAnchorU);
              this.infoWindowOptions.positionY = point.positionY - imageInfo.size.height * (1 - this.infoAnchorV);
            }
          })
        } catch (e) {
          console.error('20250516 test error')
        }
      }
    }
  }

  build() {
    Stack() {
      Column() {
        MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback })
          .width('100%')
          .height('100%');
      }.width('100%')

      Column() {
        Text('20250516 test')
          .width(200)
          .height(40)
          .backgroundColor(Color.Green)
          .textAlign(TextAlign.Center)
      }.position(
        {
          x: px2vp(this.infoWindowOptions.positionX),
          y: px2vp(this.infoWindowOptions.positionY)
        })
      .markAnchor( //设置信息窗在position的锚点,以信息窗左上角作为基准点进行偏移
        {
          x: '50%',
          y: '100%'
        }).visibility(this.show ? Visibility.Visible : Visibility.Hidden)
    }.height('100%')
  }
}

更多关于HarmonyOS鸿蒙Next地图多信息窗实现的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

开发者您好,如果想通过地图服务组件实现多信息窗效果,可以将需要展示在信息窗的信息放入自定义组件实现的marker图标中(参考自定义组件实现marker图标,在MarkerOptions参数的iconBuilder属性中添加自定义组件),然后创建多个marker标记即可。(多marker标记创建首先通过调用map.MapComponentController类的addMarker方法,该方法会返回添加的Marker实例;再通过不同的MarkerOptions参数调用该方法创建不同的marker实例。)如果以上方案无法满足开发者的诉求,请开发者提供详细的场景说明。

更多关于HarmonyOS鸿蒙Next地图多信息窗实现的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next地图多信息窗可通过Map组件的MapController实现。使用createInfoWindow方法创建信息窗,通过addInfoWindow添加到地图。可自定义信息窗内容与样式,支持点击事件。多个信息窗需管理各自ID与状态,调用showInfoWindow或hideInfoWindow控制显示。

目前HarmonyOS Next的地图服务确实只支持单个Marker的信息窗。要实现多信息窗,可以采用自定义UI叠加的方案,如你提供的代码所示。

核心思路是:

  1. 使用Stack布局将地图组件与自定义信息窗组件叠加。
  2. 通过getProjection().toScreenLocation()将地理坐标转换为屏幕坐标。
  3. 监听地图的cameraMove事件,动态更新信息窗位置。
  4. 使用positionmarkAnchor属性精确控制信息窗的显示位置。

你的实现方案是正确的,通过自定义ColumnRow等容器组件作为信息窗,配合坐标转换和事件监听,可以灵活实现多个信息窗的显示与更新。这种方法不依赖地图服务的原生信息窗能力,完全通过UI组件实现,适用于多Marker场景。

回到顶部