App Inventor 2 地图与电子围栏教程 - LocationSensor与地图组件

« 返回首页

概述

App Inventor 2内置了 Map 组件(基于OpenStreetMap),可以实现:

  • 地图显示和交互
  • 地图标记(Marker)
  • 绘制线和多边形
  • 电子围栏(地理围栏)
  • 路径追踪

Map组件位于组件面板的 Maps 分类下。

Map组件核心属性

属性 类型 说明
CenterFromString text 地图中心点(”纬度,经度”格式)
ZoomLevel number 缩放级别(1-18,越大越详细)
MapType number 地图类型(1=道路图,2=卫星图)
ShowCompass boolean 显示指南针
ShowUser boolean 显示用户位置
ShowZoom boolean 显示缩放按钮
EnableZoom boolean 允许缩放手势
LocationSensor component 关联的位置传感器

基本地图使用

显示地图并定位到指定位置

当 Screen1.初始化
  设 Map1.中心点从字符串 = "39.9042,116.4074"  ' 北京天安门
  设 Map1.缩放级别 = 15
  设 Map1.显示用户位置 = true

关联LocationSensor自动定位

当 Screen1.初始化
  设 Map1.位置传感器 = LocationSensor1  ' 关联传感器
  设 LocationSensor1.启用 = true
  设 Map1.显示用户位置 = true

当 LocationSensor1.位置改变(纬度, 经度, 海拔, 速度)
  ' 地图自动跟随用户位置
  设 Map1.中心点从字符串 = 纬度 & "," & 经度

地图标记(Marker)

添加标记

当 按钮_添加标记.被点击
  设 标记 = 创建标记(
    纬度 → 39.9042,
    经度 → 116.4074,
    标题 → "天安门",
    描述 → "北京市中心",
    颜色 → 红色
  )
  调用 Map1.添加标记(标记)

动态添加多个标记

设 地点列表 = [
  {name: "天安门", lat: 39.9042, lng: 116.4074},
  {name: "故宫", lat: 39.9163, lng: 116.3972},
  {name: "颐和园", lat: 39.9998, lng: 116.2755},
  {name: "鸟巢", lat: 39.9929, lng: 116.3966}
]

当 Screen1.初始化
  设 i = 1
  当 i ≤ 列表长度(地点列表)
    设 地点 = 列表第i项(地点列表)
    调用 Map1.创建标记(
      从字典 地点 获取 "lat",
      从字典 地点 获取 "lng",
      从字典 地点 获取 "name",
      "",
      红色)
    设 i = i + 1

标记点击事件

当 Map1.标记被点击(标记)
  设 标记.显示信息窗口()
  标签_选中.文本 = "选中:" & 标记.标题 & "(" & 标记.纬度 & ", " & 标记.经度 & ")"

绘制线条和路径

绘制两点间的线

当 按钮_画线.被点击
  调用 Map1.添加折线(
    [起点纬度, 终点纬度],  ' 纬度列表
    [起点经度, 终点经度],  ' 经度列表
    红色,                   ' 颜色
    3                       ' 线宽
  )

路径追踪

记录用户移动轨迹并在地图上绘制:

设 纬度列表 = 创建空列表
设 经度列表 = 创建空列表

当 LocationSensor1.位置改变(纬度, 经度, 海拔, 速度)
  ' 只在移动时记录(速度>0.5m/s)
  如果 速度 > 0.5
    设 纬度列表 = 添加列表项(纬度列表, 纬度)
    设 经度列表 = 添加列表项(经度列表, 经度)
    
    ' 更新路径线
    如果 列表长度(纬度列表) > 1
      调用 Map1.清除折线()
      调用 Map1.添加折线(纬度列表, 经度列表, 蓝色, 4)

电子围栏(Geofencing)

电子围栏是在地图上划定的虚拟边界,当用户进入或离开该区域时触发事件。

原理

使用 LocationSensor 持续获取位置,计算与围栏中心的距离,判断是否在围栏内。

计算两点间距离(Haversine公式)

定义 计算距离(纬度1, 经度1, 纬度2, 经度2) 返回 距离米
  设 R = 6371000  ' 地球平均半径(米)
  设 dLat = (纬度2 - 纬度1) * 数学.PI / 180
  设 dLon = (经度2 - 经度1) * 数学.PI / 180
  设 a = 数学.正弦(dLat/2) * 数学.正弦(dLat/2) +
         数学.余弦(纬度1 * 数学.PI / 180) * 数学.余弦(纬度2 * 数学.PI / 180) *
         数学.正弦(dLon/2) * 数学.正弦(dLon/2)
  设 c = 2 * 数学.反正切2(数学.平方根(a), 数学.平方根(1-a))
  返回 R * c

实现电子围栏

设 围栏中心纬度 = 39.9042
设 围栏中心经度 = 116.4074
设 围栏半径 = 500  ' 500米
设 是否在围栏内 = false

当 LocationSensor1.位置改变(纬度, 经度, 海拔, 速度)
  设 距离 = 计算距离(纬度, 经度, 围栏中心纬度, 围栏中心经度)
  
  如果 距离 ≤ 围栏半径
    如果 非 是否在围栏内
      设 是否在围栏内 = true
      调用 通知.显示信息("📍 进入围栏", "你已进入目标区域(距离中心" & 数学.保留小数(距离, 0) & "米)")
  否则
    如果 是否在围栏内
      设 是否在围栏内 = false
      调用 通知.显示信息("🚶 离开围栏", "你已离开目标区域(距离中心" & 数学.保留小数(距离, 0) & "米)")
  
  标签_距离.文本 = "距离围栏中心:" & 数学.保留小数(距离, 0) & "米"

在地图上显示围栏

当 Screen1.初始化
  ' 画一个圆形围栏(用多边形近似)
  设 纬度点 = 创建空列表
  设 经度点 = 创建空列表
  设 i = 0
  当 i < 360
    设 角度 = i * 数学.PI / 180
    ' 纬度偏移
    设 dLat = 围栏半径 / 111320  ' 1度纬度约111.32km
    设 dLon = 围栏半径 / (111320 * 数学.余弦(围栏中心纬度 * 数学.PI / 180))
    设 点纬度 = 围栏中心纬度 + dLat * 数学.余弦(角度)
    设 点经度 = 围栏中心经度 + dLon * 数学.正弦(角度)
    设 纬度点 = 添加列表项(纬度点, 点纬度)
    设 经度点 = 添加列表项(经度点, 点经度)
    设 i = i + 10  ' 每10度一个点
  
  调用 Map1.添加多边形(纬度点, 经度点, 绿色, 黄色, 2)

实战案例:儿童安全围栏

功能需求

  • 在地图上设定安全区域
  • 实时监控儿童位置
  • 离开安全区域时家长收到通知
  • 显示儿童移动轨迹

积木块代码

设 安全区域中心纬度 = 39.9042
设 安全区域中心经度 = 116.4074
设 安全半径 = 300  ' 300米
设 家长电话 = "13800138000"
设 是否安全 = true

当 Screen1.初始化
  设 LocationSensor1.启用 = true
  设 Map1.中心点从字符串 = 安全区域中心纬度 & "," & 安全区域中心经度
  设 Map1.缩放级别 = 16
  ' 在地图上画安全区域
  调用 绘制安全区域()
  ' 添加安全区域中心标记
  调用 Map1.创建标记(安全区域中心纬度, 安全区域中心经度, "🏠 家", "安全区域中心", 绿色)

当 LocationSensor1.位置改变(纬度, 经度, 海拔, 速度)
  设 距离 = 计算距离(纬度, 经度, 安全区域中心纬度, 安全区域中心经度)
  标签_状态.文本 = "距离家:" & 数学.保留小数(距离, 0) & "米"
  
  ' 更新儿童位置标记
  设 Map1.中心点从字符串 = 纬度 & "," & 经度
  
  如果 距离 > 安全半径
    如果 是否安全
      设 是否安全 = false
      标签_状态.文本颜色 = 红色
      ' 发送短信通知家长
      调用 短信组件.发送短信(家长电话, "⚠️ 儿童已离开安全区域!当前位置:" & 纬度 & "," & 经度)
  否则
    如果 非 是否安全
      设 是否安全 = true
      标签_状态.文本颜色 = 绿色
      调用 短信组件.发送短信(家长电话, "✅ 儿童已回到安全区域")

常见问题

Q1: Map组件显示空白?

  • 确保有网络连接(Map使用OpenStreetMap在线瓦片)
  • 检查CenterFromString格式是否正确(”纬度,经度”,注意纬度在前)
  • 确认ZoomLevel设置合理(建议10-16)

Q2: 位置更新不频繁?

  • LocationSensor的 DistanceInterval 设小一些(如1米)
  • 但注意频繁更新会增加耗电

Q3: 如何计算两个GPS点之间的距离?

使用上面提供的Haversine公式计算函数。短距离(<1km)精度足够。

Q4: 电子围栏后台运行?

App Inventor应用在后台时传感器会被系统暂停。解决方案:

  • 设置 TimerAlwaysFires = true
  • 使用前台服务(需要扩展)
  • 或接受App Inventor的限制,只在App前台运行时监控

总结

功能 组件 方法
地图显示 Map 设置中心点和缩放级别
定位 LocationSensor LocationChanged事件
标记 Map.CreateMarker 添加图标和信息窗口
路径绘制 Map.AddPolyline 纬度/经度列表
电子围栏 LocationSensor + 数学 Haversine距离计算
位置追踪 LocationSensor + Map 实时更新位置和路径

版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。

文档反馈