Skip to content
Back to skills

Hmos Map Kit Bubble

ASecurity

在地图指定位置添加气泡,支持四方向图标、碰撞规则、位置优化、动画和点击事件,适用于道路测速、拥堵情况显示场景

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
developmenttypescriptgitapibackend

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add IsKenKenYa/skills --skill hmos-map-kit-bubble --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hmos Map Kit Bubble?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hmos Map Kit Bubble
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iskenkenya-hmos-map-kit-bubble/badge)](https://www.skillsdirectory.com/skills/iskenkenya-hmos-map-kit-bubble)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hmos-map-kit-bubble
description: 在地图指定位置添加气泡,支持四方向图标、碰撞规则、位置优化、动画和点击事件,适用于道路测速、拥堵情况显示场景
---

# 气泡技能

## 功能描述

气泡用于在地图道路上的指定位置显示测速、拥堵情况等信息。支持设置四个方向的图标(传入的图标宽高需相同),支持设置图标碰撞规则,支持设置候选坐标段使气泡在最佳线段位置上,支持设置图标动画,支持添加点击事件。

**核心能力**:
- 在地图指定位置添加气泡覆盖物
- 支持设置四个方向的图标(必须提供4个图标)
- 支持碰撞规则设置(forceVisible、priority)
- 支持显示层级控制(minZoom、maxZoom)
- 支持缩放动画效果
- 支持点击事件监听

## 使用场景

### 触发词
- "添加气泡"
- "地图气泡"
- "道路测速显示"
- "拥堵情况标注"
- "限速标志"
- "Map Kit气泡"

### 能做
- 在地图上添加单个或多个气泡
- 设置气泡的四个方向图标
- 配置气泡的碰撞优先级和显示规则
- 设置气泡的显示层级范围
- 为气泡添加缩放动画效果
- 监听气泡的点击事件

### 绝不做
- 不支持在非道路位置添加气泡
- 不支持少于4个方向的图标
- 不支持宽高不同的图标
- 不处理地图初始化失败的情况(需用户自行处理)

### 补充
- 图标必须存放在resources/rawfile目录下
- 图标宽高必须相同
- 气泡位置基于多个候选坐标段计算最佳位置
- 需要在地图初始化回调中添加气泡

## 调用规范和规则

### 输入约束
- 图标数量:必须提供4个方向的图标
- 图标宽高:必须相同
- 图标格式:支持jpg、jpeg、png、gif、webp、svg
- 图标路径:必须存放在resources/rawfile目录下
- 坐标范围:纬度[-90, 90],经度[-180, 180]
- 层级范围:minZoom和maxZoom范围[2, 20]
- priority范围:number类型,数值越大优先级越低

### 执行约束
- 必须在地图初始化完成后添加气泡
- 每次调用addBubble添加一个气泡
- 异步API调用,使用Promise回调
- 设置动画需先调用setAnimation再调用startAnimation

### 内容约束
- 禁止使用虚假的API名称
- 禁止推测API参数类型
- 禁止使用高危函数(eval、exec等)
- 必须进行参数校验和异常捕获
- 必须处理错误码返回

### 降级约束
- 图标加载失败:记录错误日志,使用默认图标
- 气泡创建失败:记录错误码和message,提示用户
- 地图未初始化:提示用户等待地图初始化完成
- 网络异常:重试最多3次,记录失败原因

## 调用流程和步骤

### 步骤1:准备阶段

**导入模块**:
```typescript
import { MapComponent, mapCommon, map } from '@kit.MapKit';
import { AsyncCallback } from '@kit.BasicServicesKit';
```

**初始化地图组件**:
```typescript
@Entry
@Component
struct BubbleDemo {
  private mapOptions?: mapCommon.MapOptions;
  private mapController?: map.MapComponentController;
  private callback?: AsyncCallback<map.MapComponentController>;
  private bubble?: map.Bubble;
  
  aboutToAppear(): void {
    this.mapOptions = {
      position: {
        target: {
          latitude: 39.918,
          longitude: 116.397
        },
        zoom: 14
      }
    };
  }
}
```

**参数校验**:
```typescript
function validateBubbleParams(params: mapCommon.BubbleParams): boolean {
  if (!params.positions || params.positions.length === 0) {
    console.error('positions参数不能为空');
    return false;
  }
  if (!params.icons || params.icons.length !== 4) {
    console.error('必须提供4个方向的图标');
    return false;
  }
  if (params.minZoom < 2 || params.maxZoom > 20 || params.minZoom > params.maxZoom) {
    console.error('minZoom和maxZoom必须在[2, 20]范围内,且minZoom <= maxZoom');
    return false;
  }
  return true;
}
```

### 步骤2:创建气泡参数

**定义气泡参数**:
```typescript
let bubbleOptions: mapCommon.BubbleParams = {
  positions: [[{
    latitude: 39.918,
    longitude: 116.397
  }]],
  icons: [
    'speed_limit_10.png',
    'speed_limit_20.png',
    'speed_limit_30.png',
    'speed_limit_40.png'
  ],
  forceVisible: true,
  priority: 3,
  minZoom: 2,
  maxZoom: 20,
  visible: true,
  zIndex: 1
};
```

### 步骤3:调用API添加气泡

**添加气泡示例代码**:
```typescript
this.callback = async (err, mapController) => {
  if (!err) {
    this.mapController = mapController;
    
    if (!validateBubbleParams(bubbleOptions)) {
      console.error('气泡参数校验失败');
      return;
    }
    
    try {
      this.bubble = await this.mapController.addBubble(bubbleOptions);
      console.info('气泡添加成功');
    } catch (e) {
      console.error(`Failed to create the bubble, code is:${e.code}, message is ${e.message}`);
    }
  } else {
    console.error(`Failed to initialize the map, code is:${err.code}, message is ${err.message}`);
  }
};
```

### 步骤4:监听气泡点击事件

**设置点击事件监听**:
```typescript
let callback = (bubble: map.Bubble) => {
  console.info("bubbleClick", `callback bubble = ${bubble.getId()}`);
};
this.mapController?.on("bubbleClick", callback);
```

### 步骤5:设置气泡动画

**创建缩放动画**:
```typescript
let animation: map.ScaleAnimation = new map.ScaleAnimation(1, 3, 1, 3);
animation.setDuration(3000);

let callbackStart = () => {
  console.info("animationStart", `callback`);
};
animation.on("animationStart", callbackStart);

let callbackEnd = () => {
  console.info("animationEnd", `callback`);
};
animation.on("animationEnd", callbackEnd);

animation.setFillMode(map.AnimationFillMode.BACKWARDS);
animation.setRepeatMode(map.AnimationRepeatMode.REVERSE);
animation.setInterpolator(Curve.Linear);
animation.setRepeatCount(100);
```

**设置并启动动画**:
```typescript
this.bubble.setAnimation(animation);
this.bubble.startAnimation();
```

### 步骤6:错误处理

**错误处理代码**:
```typescript
try {
  this.bubble = await this.mapController.addBubble(bubbleOptions);
} catch (error) {
  switch (error.code) {
    case 401:
      console.error('Invalid input parameter');
      break;
    case 1002601001:
      console.error('The object to be operated does not exist');
      break;
    default:
      console.error('Unknown error:', error.message);
  }
}
```

### 步骤7:降级处理

**图标加载失败降级**:
```typescript
async function loadBubbleWithFallback(mapController: map.MapComponentController, options: mapCommon.BubbleParams): Promise<map.Bubble | null> {
  try {
    return await mapController.addBubble(options);
  } catch (e) {
    if (e.code === 1002601001) {
      console.warn('图标加载失败,尝试使用默认图标');
      const defaultIcons = ['default1.png', 'default2.png', 'default3.png', 'default4.png'];
      options.icons = defaultIcons;
      try {
        return await mapController.addBubble(options);
      } catch (retryError) {
        console.error('降级方案失败:', retryError.message);
        return null;
      }
    }
    console.error('气泡创建失败:', e.message);
    return null;
  }
}
```

## 错误码说明

| 错误码 | 说明 | 解决方法 |
|-------|------|---------|
| 401 | Invalid input parameter | 检查参数类型和取值范围,确保positions非空,icons包含4个元素 |
| 1002601001 | The object to be operated does not exist | 确保地图已初始化完成,mapController不为空 |
| 1002601005 | Failed to generate the icon of the customized component | 检查图标路径和格式,确保图标存在于resources/rawfile目录 |

## 编译和修复问题

### 依赖声明
```json
{
  "dependencies": {
    "@kit.MapKit": "^4.1.0",
    "@kit.BasicServicesKit": "^4.1.0"
  }
}
```

### 环境要求
- HarmonyOS版本:4.1.0(11)及以上
- 开发环境:DevEco Studio
- 运行环境:Stage模型
- 图标资源:必须存放在resources/rawfile目录

### 常见编译问题

**问题1:图标路径找不到**
```
Error: Cannot find module 'speed_limit_10.png'
```
**解决方法**:确保图标文件存放在resources/rawfile目录下,使用相对路径引用

**问题2:API导入失败**
```
Error: Cannot find name 'mapCommon'
```
**解决方法**:确保正确导入模块:`import { mapCommon } from '@kit.MapKit';`

**问题3:气泡不可见**
```
气泡添加成功但地图上不显示
```
**解决方法**:检查visible属性为true,minZoom和maxZoom范围是否包含当前地图层级,检查priority和forceVisible设置

## 常见问题与解决方法

### Q1:图标显示不正确
**原因**:图标路径错误或图标格式不支持
**解决方法**:
- 确认图标存放在resources/rawfile目录下
- 检查图标格式是否为支持的格式(jpg、jpeg、png、gif、webp、svg)
- 确认图标宽高相同

### Q2:气泡不显示
**原因**:visible属性设置错误或层级范围不匹配
**解决方法**:
- 设置visible为true
- 确认minZoom和maxZoom范围包含当前地图缩放层级
- 检查priority和forceVisible碰撞规则设置

### Q3:碰撞规则不生效
**原因**:priority设置错误或forceVisible未设置
**解决方法**:
- priority数值越大优先级越低,合理设置优先级
- 设置forceVisible为true使气泡碰撞后仍能显示

### Q4:动画不播放
**原因**:未调用startAnimation或动画参数设置错误
**解决方法**:
- 设置动画后必须调用startAnimation()
- 检查动画duration、repeatCount等参数设置
- 确认setAnimation已调用

### Q5:点击事件不触发
**原因**:未设置事件监听或事件类型错误
**解决方法**:
- 使用mapController.on("bubbleClick", callback)设置监听
- 确认事件类型为"bubbleClick"

## 输出结果报告

执行完成后输出以下信息:

```json
{
  "status": "success",
  "bubbleId": "气泡唯一标识",
  "positions": "[[{latitude: 39.918, longitude: 116.397}]]",
  "icons": ["speed_limit_10.png", "speed_limit_20.png", "speed_limit_30.png", "speed_limit_40.png"],
  "visible": true,
  "minZoom": 2,
  "maxZoom": 20,
  "priority": 3,
  "apiUsed": [
    "mapCommon.BubbleParams",
    "map.MapComponentController.addBubble",
    "map.Bubble"
  ]
}
```

## 参考文档

- [API开发指南 - 气泡](references/map-bubble.md)
- [BubbleParams API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-common)
- [addBubble API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-mapcomponentcontroller)
- [Bubble API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-bubble)
- [BasePriorityOverlay API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-basepriorityoverlay)

## 完整示例代码

- [ArkTS完整示例](assets/bubble_demo.ets)
- [动画示例](assets/bubble_animation.ets)
- [点击事件示例](assets/bubble_click.ets)

## 测试用例

### 正向测试用例
- [添加单个气泡](tests/test_add_single_bubble.ets):测试添加单个气泡的基本功能
- [添加多个气泡](tests/test_add_multiple_bubbles.ets):测试添加多个气泡的功能
- [设置动画](tests/test_bubble_animation.ets):测试气泡动画设置和播放
- [点击事件](tests/test_bubble_click.ets):测试气泡点击事件监听

### 边界测试用例
- [层级范围边界](tests/test_zoom_boundary.ets):测试minZoom=2和maxZoom=20的边界情况
- [坐标范围边界](tests/test_coordinate_boundary.ets):测试纬度和经度的边界值
- [priority边界](tests/test_priority_boundary.ets):测试priority的极限值

### 异常测试用例
- [图标数量错误](tests/test_icon_count_error.ets):测试少于4个图标的情况
- [图标路径错误](tests/test_icon_path_error.ets):测试图标路径不存在的情况
- [地图未初始化](tests/test_map_not_initialized.ets):测试地图未初始化时添加气泡
- [参数类型错误](tests/test_param_type_error.ets):测试参数类型不正确的情况

Files in this skill

  • SUB_SKILL.md11.9 KB
  • assets/bubble_animation.ets2.6 KB
  • assets/bubble_click.ets2.3 KB
  • assets/bubble_demo.ets2.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…