【HarmonyOS实战】 地图Marker标记:自定义图标、信息窗口与点击事件
2026/6/5 17:51:00 网站建设 项目流程

文章目录

    • 前言
    • 一、addMapMaker 方法解析
    • 二、MarkerOptions 每个参数详解
      • 2.1 position:坐标位置
      • 2.2 anchor:锚点
      • 2.3 icon:自定义图标
      • 2.4 flat:贴地模式
      • 2.5 zIndex:层叠顺序
      • 2.6 alpha:透明度
      • 2.7 collisionRule:碰撞规则
    • 三、批量添加 Marker
    • 四、Marker 点击事件
    • 五、信息窗口(InfoWindow)
    • 六、底部弹窗关闭时重置动画
    • 七、完整的 Marker 生命周期
    • 总结

前言

地图上那些能点击的图标叫做Marker(标记),是地图应用最核心的 UI 元素之一。在附近加油站里,每个加油站在地图上都有一个自定义图标(加油站 SVG 图案),点击后标记会放大,底部列表也会出现。

这篇文章详细讲 Marker 的添加、自定义图标配置、信息窗口显示以及点击事件处理。

项目预览

一、addMapMaker 方法解析

// MapUtil.etsasyncaddMapMaker(latitude:number,longitude:number,mapController:map.MapComponentController):Promise<void>{letmarkerOptions:mapCommon.MarkerOptions={position:{latitude:latitude,longitude:longitude},rotation:0,// 旋转角度(0度,即不旋转)visible:true,// 是否可见zIndex:0,// 层叠顺序alpha:1,// 透明度(1=完全不透明)anchorU:0.5,// 锚点X(0-1,0.5=水平居中)anchorV:1,// 锚点Y(0-1,1=底部对齐到坐标点)clickable:true,// 是否可点击flat:true,// 是否贴地(随地图倾斜)icon:'station.svg',// 自定义图标(SVG文件名)collisionRule:mapCommon.CollisionRule.NAME,// 碰撞规则};// 添加 MarkerawaitmapController.addMarker(markerOptions);}

二、MarkerOptions 每个参数详解

2.1 position:坐标位置

position:{latitude:latitude,longitude:longitude}

Marker 在地图上显示的位置,使用 GCJ02 坐标(中国境内)。

2.2 anchor:锚点

anchorU:0.5,// 水平方向锚点(0=左边, 0.5=中间, 1=右边)anchorV:1,// 垂直方向锚点(0=顶部, 0.5=中间, 1=底部)

锚点决定 Marker 图标的哪个点对应地图坐标:

anchorU=0.5, anchorV=1 的效果: ┌────────────┐ │ │ │ [图标] │ │ │ └─────●──────┘ ↑ 图标底部中央对准坐标点(像图钉一样)

对于加油站这种图标,anchorV=1(底部对齐)让图标的底部尖端精确指向坐标点,视觉上更准确。

2.3 icon:自定义图标

icon:'station.svg',// 使用 SVG 文件作为图标

icon指定图标文件名,文件放在resources/base/media/目录下。支持 PNG、SVG 等格式。

为什么选 SVG?

格式优点缺点
PNG支持复杂图案放大会模糊,需要提供@2x/@3x多分辨率
SVG矢量,任意放大不失真,文件小不支持过于复杂的效果

地图标记需要在不同缩放级别下保持清晰,SVG 是更好的选择。

2.4 flat:贴地模式

flat:true,
  • flat: true:标记贴在地图表面,地图倾斜时标记也跟着倾斜(更立体的感觉)
  • flat: false(默认):标记始终面向用户(始终垂直于屏幕)

2.5 zIndex:层叠顺序

zIndex:0,

当多个 Marker 重叠时,zIndex越大的显示在上层。默认 0,如果你希望某个重要标记始终在最上面,给它设置更大的 zIndex。

2.6 alpha:透明度

alpha:1,// 1=完全不透明,0=完全透明,0.5=半透明

2.7 collisionRule:碰撞规则

collisionRule:mapCommon.CollisionRule.NAME,

当多个 Marker 在屏幕上位置太近时,如何处理碰撞:

碰撞规则说明
NAME按名称决定显示优先级
NONE不处理碰撞(都显示)

三、批量添加 Marker

// GasStationPage.ets - callback 里this.stationInfoList.forEach(async(stationItem:StationData)=>{awaitmapUtil.addMapMaker(stationItem.latitude,stationItem.longitude,this.mapControllerasmap.MapComponentController);});

遍历加油站列表,为每个加油站在对应坐标添加一个 Marker。注意这里用的是async forEach——虽然语法上没问题,但有一个潜在问题:forEach 不能正确等待 async 回调完成

更严谨的写法:

// 更严谨:用 for...of + await 确保顺序添加for(letstationItemofthis.stationInfoList){awaitmapUtil.addMapMaker(stationItem.latitude,stationItem.longitude,this.mapControllerasmap.MapComponentController);}

对于这个场景,并发添加还是顺序添加差别不大,forEach写法更简洁,但要知道它不是真正的顺序等待。

四、Marker 点击事件

在 GasStationPage 的 callback 里监听 Marker 点击:

this.mapController.on('markerClick',(marker)=>{// 1. 显示底部加油站列表this.isShow=true;// 2. 显示标记的信息窗口(弹出小气泡)marker.setInfoWindowVisible(true);// 3. 记录当前点击的标记(用于后续重置)this.curMarker=marker;// 4. 设置放大比例并播放动画this.imageScale=1.5;mapUtil.imageAnimation(marker,this.imageScale);// 5. 移动地图到该标记位置mapUtil.moveToCurrentPosition(marker.getPosition().latitude,marker.getPosition().longitude,mapController);});

marker 对象的常用方法

方法作用
marker.getPosition()获取标记的经纬度
marker.setInfoWindowVisible(true)显示信息窗口(小气泡)
marker.setAnimation(animation)设置动画
marker.startAnimation()启动动画
marker.setVisible(true)设置可见性
marker.setIcon('newIcon.png')动态更换图标

五、信息窗口(InfoWindow)

marker.setInfoWindowVisible(true);// 显示信息窗口marker.setInfoWindowVisible(false);// 隐藏信息窗口

信息窗口是点击 Marker 后弹出的小气泡,默认显示 Marker 的 title 和 snippet:

letmarkerOptions:mapCommon.MarkerOptions={// ...title:'中国石化AA站',// 信息窗口标题snippet:'N市J区XX大街587号',// 信息窗口副标题};

项目里没有设置titlesnippet,所以信息窗口是空的。调用setInfoWindowVisible(true)只是触发一个空白气泡,实际信息展示在底部的bindSheet里。

六、底部弹窗关闭时重置动画

当底部弹窗关闭时,需要把放大的 Marker 恢复原始大小:

// GasStationPage.ets - bindSheet 的 onWillDismiss 回调.bindSheet($$this.isShow,this.bindBuilder(),{// ...onWillDismiss:((dismissSheetAction:DismissSheetAction)=>{if(this.curMarker){this.imageScale=1;// 恢复原始大小mapUtil.imageAnimation(this.curMarker,this.imageScale);// 播放缩小动画}dismissSheetAction.dismiss();// 确认关闭弹窗})});

七、完整的 Marker 生命周期

页面进入 → init() └─> addMapMaker() × 4 (添加4个加油站标记) 用户点击标记: └─> on('markerClick') ├─> setInfoWindowVisible(true) (显示气泡) ├─> imageAnimation(scale=1.5) (放大动画) ├─> moveToCurrentPosition() (移动镜头) └─> isShow = true (显示底部列表) 用户关闭底部列表: └─> onWillDismiss └─> imageAnimation(scale=1) (缩小恢复)

总结

Marker 是地图的核心 UI 元素:

  1. 创建:构建MarkerOptions(坐标、图标、锚点、可见性等)
  2. 添加mapController.addMarker(markerOptions),注意是 async 的
  3. 监听点击mapController.on('markerClick', callback),callback 接收 marker 对象
  4. 动态操作:通过 marker 对象的方法控制显示/隐藏/动画

自定义图标使用 SVG,锚点anchorV=1让图标底部对准坐标点,体验更准确。

下一篇讲相机动画——地图镜头移动是怎么实现流畅动画效果的。

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

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

立即咨询