App Inventor 2 地图导航与电子围栏教程

本文涵盖:实时定位显示、地图标记、调用高德/百度导航、电子围栏(进出区域提醒)。

一、核心组件

组件类型作用
地图(Map)界面组件显示地图、添加标记
标记(Marker)地图子组件地图上的点标记
位置传感器(LocationSensor)传感器获取GPS坐标
活动启动器(ActivityStarter)连接调起外部导航App

二、实时定位显示

2.1 界面设计

  • 地图组件(充满屏幕)
  • 标记组件(放在地图内)
  • 标签:显示坐标
  • 位置传感器(不可见)

2.2 代码块

// 屏幕初始化:启用位置传感器
当 Screen1.初始化 时
  设置 位置传感器1.启用 = 真
  // 设置地图初始中心(北京)
  设置 地图1.中心坐标 = "39.9042, 116.4074"
  设置 地图1.缩放级别 = 15

// 位置变化时更新地图
当 位置传感器1.位置改变 时(纬度, 经度, 高度, 速度)
  // 更新标记位置
  设置 标记1.纬度 = 纬度
  设置 标记1.经度 = 经度
  
  // 地图跟随移动
  设置 地图1.中心坐标 = 合并字符串(纬度, ", ", 经度)
  
  // 显示坐标
  设置 标签_坐标.文本 = 合并字符串(
    "纬度:", 四舍五入到小数点后6位(纬度), "\n",
    "经度:", 四舍五入到小数点后6位(经度), "\n",
    "精度:", 位置传感器1.精度, "米"
  )

三、地图标记(Marker)

3.1 添加固定标记

// 在地图上添加一个标记
设置 标记1.纬度 = 39.9042
设置 标记1.经度 = 116.4074
设置 标记1.标题 = "天安门"
设置 标记1.描述 = "北京市中心"
设置 标记1.图片 = "marker_red.png"  // 自定义图标

3.2 动态添加多个标记

初始化全局变量 地点列表 = [
  创建字典(["name","天安门"],["lat",39.9042],["lng",116.4074]),
  创建字典(["name","故宫"],["lat",39.9163],["lng",116.3972]),
  创建字典(["name","颐和园"],["lat",39.9999],["lng",116.2755])
]

当 按钮_显示地点.被点击 时
  对于 每个 地点 在 全局变量 地点列表 中
    初始化局部变量 名称 = 获取键的值(地点, "name", "")
    初始化局部变量 纬度 = 获取键的值(地点, "lat", 0)
    初始化局部变量 经度 = 获取键的值(地点, "lng", 0)
    
    // 动态创建标记(需要DynamicComponents扩展)
    调用 DynamicComponents1.创建("Marker", 地图1, 名称)
    调用 DynamicComponents1.设置属性(名称, "Latitude", 纬度)
    调用 DynamicComponents1.设置属性(名称, "Longitude", 经度)
    调用 DynamicComponents1.设置属性(名称, "Title", 名称)

// 点击标记时显示信息
当 标记1.被点击 时
  调用 对话框1.显示消息对话框(
    合并字符串(标记1.标题, "\n", 标记1.描述),
    "地点信息", "确定")

四、调起外部导航App

App Inventor 2 没有内置导航功能,通过 ActivityStarter 调起高德/百度地图导航。

4.1 调起高德地图导航

初始化全局变量 目标纬度 = 39.9042
初始化全局变量 目标经度 = 116.4074
初始化全局变量 目标名称 = "天安门"

当 按钮_导航.被点击 时
  // 高德地图导航URI
  设置 活动启动器1.动作 = "android.intent.action.VIEW"
  设置 活动启动器1.数据URI = 合并字符串(
    "androidamap://navi?sourceApplication=ai2app",
    "&poiname=", 全局变量 目标名称,
    "&lat=", 全局变量 目标纬度,
    "&lon=", 全局变量 目标经度,
    "&dev=0&style=2"
  )
  设置 活动启动器1.活动包名 = "com.autonavi.minimap"
  调用 活动启动器1.启动活动

4.2 调起百度地图导航

当 按钮_百度导航.被点击 时
  设置 活动启动器1.动作 = "android.intent.action.VIEW"
  设置 活动启动器1.数据URI = 合并字符串(
    "baidumap://map/direction?destination=latlng:",
    全局变量 目标纬度, ",", 全局变量 目标经度,
    "|name:", 全局变量 目标名称,
    "&mode=driving&coord_type=gcj02"
  )
  设置 活动启动器1.活动包名 = "com.baidu.BaiduMap"
  调用 活动启动器1.启动活动

4.3 通用方案(浏览器打开Google Maps)

当 按钮_谷歌地图.被点击 时
  设置 活动启动器1.动作 = "android.intent.action.VIEW"
  设置 活动启动器1.数据URI = 合并字符串(
    "https://maps.google.com/maps?daddr=",
    全局变量 目标纬度, ",", 全局变量 目标经度
  )
  调用 活动启动器1.启动活动

五、电子围栏(进出区域提醒)

电子围栏:当用户进入或离开某个区域时,自动触发提醒。

5.1 原理

计算当前位置与围栏中心的距离,与围栏半径比较:
  • 距离 < 半径 → 在围栏内
  • 距离 > 半径 → 在围栏外

5.2 距离计算公式(Haversine公式)

// 计算两点之间的距离(米)
定义 计算距离(纬1, 经1, 纬2, 经2)
  初始化局部变量 R = 6371000  // 地球半径(米)
  初始化局部变量 φ1 = 纬1 * 3.14159 / 180
  初始化局部变量 φ2 = 纬2 * 3.14159 / 180
  初始化局部变量 Δφ = (纬2 - 纬1) * 3.14159 / 180
  初始化局部变量 Δλ = (经2 - 经1) * 3.14159 / 180
  
  初始化局部变量 a = 正弦(Δφ/2)^2 + 余弦(φ1) * 余弦(φ2) * 正弦(Δλ/2)^2
  初始化局部变量 c = 2 * 反正切2(平方根(a), 平方根(1-a))
  
  返回 R * c

5.3 电子围栏完整代码

初始化全局变量 围栏中心纬度 = 39.9042
初始化全局变量 围栏中心经度 = 116.4074
初始化全局变量 围栏半径 = 500    // 500米
初始化全局变量 上次状态 = "未知"  // "内" 或 "外"

当 位置传感器1.位置改变 时(纬度, 经度, 高度, 速度)
  // 计算与围栏中心的距离
  初始化局部变量 距离 = 调用 计算距离(
    纬度, 经度,
    全局变量 围栏中心纬度, 全局变量 围栏中心经度
  )
  
  初始化局部变量 当前状态 = 如果 距离 <= 全局变量 围栏半径 则 "内" 否则 "外"
  
  // 状态变化时触发提醒
  如果 当前状态 ≠ 全局变量 上次状态 则
    如果 当前状态 = "内" 则
      // 进入围栏
      调用 对话框1.显示消息对话框(
        合并字符串("📍 已进入围栏区域\n距中心:", 四舍五入(距离), "米"),
        "围栏提醒", "确定")
      调用 音效1.播放
    否则
      // 离开围栏
      调用 对话框1.显示消息对话框(
        "🚶 已离开围栏区域",
        "围栏提醒", "确定")
    
    设置 全局变量 上次状态 = 当前状态
  
  // 更新显示
  设置 标签_距离.文本 = 合并字符串(
    "距围栏中心:", 四舍五入(距离), "米\n",
    "状态:围栏", 当前状态
  )

六、实战:考勤打卡系统(电子围栏应用)

6.1 功能设计

  • 设定公司位置为围栏中心,半径200米
  • 进入围栏时自动记录上班打卡
  • 离开围栏时自动记录下班打卡
  • 打卡记录保存到网络微数据库

6.2 代码块

初始化全局变量 公司纬度 = 39.9042
初始化全局变量 公司经度 = 116.4074
初始化全局变量 打卡半径 = 200
初始化全局变量 已打卡上班 = 假
初始化全局变量 已打卡下班 = 假

当 位置传感器1.位置改变 时(纬度, 经度, 高度, 速度)
  初始化局部变量 距离 = 调用 计算距离(纬度, 经度, 全局变量 公司纬度, 全局变量 公司经度)
  
  如果 距离 <= 全局变量 打卡半径 则
    // 在公司范围内
    如果 全局变量 已打卡上班 = 假 则
      // 上班打卡
      初始化局部变量 时间 = 调用 计时器1.格式化日期时间(调用 计时器1.现在, "HH:mm:ss")
      调用 网络微数据库1.存储值(
        合并字符串("checkin_", 当前用户, "_", 今日日期),
        时间
      )
      设置 全局变量 已打卡上班 = 真
      设置 标签_状态.文本 = 合并字符串("✅ 上班打卡:", 时间)
  否则
    // 离开公司
    如果 全局变量 已打卡上班 = 真 且 全局变量 已打卡下班 = 假 则
      // 下班打卡
      初始化局部变量 时间 = 调用 计时器1.格式化日期时间(调用 计时器1.现在, "HH:mm:ss")
      调用 网络微数据库1.存储值(
        合并字符串("checkout_", 当前用户, "_", 今日日期),
        时间
      )
      设置 全局变量 已打卡下班 = 真
      设置 标签_状态.文本 = 合并字符串("✅ 下班打卡:", 时间)

七、常见问题

Q1:位置传感器获取不到坐标?

  • 确认已授予位置权限(Android 6+需运行时授权)
  • 在室外或靠近窗户,GPS信号更好
  • 可先用网络定位(精度低但快):设置 位置传感器1.使用GPS = 假

Q2:地图显示空白?

  • 检查网络连接(地图需要联网加载瓦片)
  • 默认使用OpenStreetMap,国内访问可能较慢

Q3:高德地图调起失败?

  • 确认手机已安装高德地图
  • 检查包名是否正确(com.autonavi.minimap
  • 可先用通用浏览器方案作为备选

Q4:电子围栏精度不够?

  • GPS精度通常10-20米,围栏半径建议 >= 100米
  • 可用 位置传感器1.精度 属性过滤低精度数据

参考资料


文档版本:2026.03 | 作者:App Inventor 2 中文网 www.fun123.cn

参考资料与版权声明

原文来源

版权声明

本文档基于 MIT App Inventor 官方文档及社区资源整理,版权归原作者所有:
  • MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权
  • MIT App Inventor Community 帖子版权归原作者所有
本文档由 ai2claw 🐝 整理,仅供学习参考,如有侵权请联系删除。