功能跳转主流地图APP实现步骤1.引入外部库map_launcher: ^4.5.0 #检测手机是否安装了主流地图 APP2.增加导航弹窗void showBottomSheetDialog(BuildContext context){ showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)) ), builder: (BuildContext context){ return Container( padding: EdgeInsets.symmetric( vertical: 20, //horizontal: 10 ), height: 250, child: Column( children: [ GestureDetector( onTap: () async { goGaodeMap(); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFF4AC6AD).withOpacity(0.8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(高德地图,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), SizedBox(height: 5,), GestureDetector( onTap: (){ //跳转百度地图 goBaiduMap(); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFF4AC6AD).withOpacity(0.8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(百度地图,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), SizedBox(height: 25,), Container( height: 1, width: double.infinity, color: Color(0xFFA8A8A8), ), SizedBox(height: 15,), GestureDetector( onTap: (){ Navigator.pop(context); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFFA8A8A8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(取消,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), ], ), ); } ); }3.跳转地图的具体方法///跳转高德地图 Futurevoid goGaodeMap() async{ try { if (_currentPosition null) { Fluttertoast.showToast(msg: 请先获取当前位置); return; } // 检查高德地图是否安装 bool isAmapAvailable await map_launcher.MapLauncher.isMapAvailable(map_launcher.MapType.amap); if (isAmapAvailable) { print(高德地图已安装准备跳转); if (_currentAddress ! null) { await map_launcher.MapLauncher.showMarker( mapType: map_launcher.MapType.amap, coords: map_launcher.Coords( _currentPosition!.latitude, _currentPosition!.longitude ), title: , // 使用设备名称 description: 耳机位置, // 可选描述 ); print(跳转成功); } else { print(无法获取耳机位置); Fluttertoast.showToast(msg: 无法获取耳机位置); } } else { print(高德地图未安装); Fluttertoast.showToast(msg: 请先安装高德地图); } } catch (e) { print(跳转失败: $e); Fluttertoast.showToast(msg: 跳转失败); } Navigator.pop(context); } ///跳转百度地图 Futurevoid goBaiduMap() async{ try { if (_currentPosition null) { Fluttertoast.showToast(msg: 请先获取当前位置); return; } // 检查百度地图是否安装 bool isBaiduAvailable await map_launcher.MapLauncher.isMapAvailable(map_launcher.MapType.baidu); if (isBaiduAvailable) { print(高德地图已安装准备跳转); //耳机的位置 if (_currentAddress ! null) { await map_launcher.MapLauncher.showMarker( mapType: map_launcher.MapType.baidu, coords: map_launcher.Coords( _currentPosition!.latitude, _currentPosition!.longitude ), title: , // 使用设备名称 description: 耳机位置, // 可选描述 ); print(跳转成功); } else { print(无法获取耳机位置); Fluttertoast.showToast(msg: 无法获取耳机位置); } } else { print(高德地图未安装); Fluttertoast.showToast(msg: 请先安装百度地图); } } catch (e) { print(跳转失败: $e); Fluttertoast.showToast(msg: 跳转失败); } Navigator.pop(context); }代码实例import package:flutter/cupertino.dart; import package:flutter/material.dart; import package:fluttertoast/fluttertoast.dart; import package:geocoding/geocoding.dart; import package:geolocator/geolocator.dart; import package:map_launcher/map_launcher.dart as map_launcher; import location_service.dart; /// 设备查找页面 class DeviceFindPage extends StatefulWidget { const DeviceFindPage({super.key}); override StateStatefulWidget createState() _DeviceFindPageState(); } class _DeviceFindPageState extends StateDeviceFindPage { // 定位相关 final LocationService _locationService LocationService(); //定位服务实例 Position? _currentPosition; //当前位置 String _currentAddress ; //当前地址 bool _isLoadingLocation false; //加载状态 bool _hasLocationPermission false; //权限状态 // 文本资源 String findDevice 查找设备; String tapRing 点击唤醒; String tapRingTips 温馨提示唤醒设备后会发出声音请注意聆听; String addressTips 温馨提示app会标记设备断联前的最后位置您可以打开点击右边图标转进导航软件查看位置; override void initState() { super.initState(); // 设置定位回调 _setupLocationCallbacks(); // 页面加载时自动获取位置 WidgetsBinding.instance.addPostFrameCallback((_) { _getLocationAndAddress(); }); } override void dispose() { // 释放定位资源 _locationService.dispose(); super.dispose(); } //设置定位回调 void _setupLocationCallbacks() { _locationService.onLocationUpdated (Position position) { if (mounted) { setState(() { _currentPosition position; _hasLocationPermission true; }); // 位置更新时重新获取地址 _getAddressFromLatLng(position.latitude, position.longitude); } }; _locationService.onError (String error) { // Log.d(定位错误: $error); if (mounted) { setState(() { _currentAddress 定位失败: $error; _isLoadingLocation false; }); // 显示提示 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(定位错误: $error), backgroundColor: Colors.red, ), ); } }; } //获取位置和地址 Futurevoid _getLocationAndAddress() async { if (_isLoadingLocation) return; setState(() { _isLoadingLocation true; _currentAddress 正在获取位置...; }); try { // 获取单次定位 Position? position await _locationService.getCurrentLocation(); if (position ! null mounted) { setState(() { _currentPosition position; _hasLocationPermission true; }); // 获取地址 await _getAddressFromLatLng(position.latitude, position.longitude); } } catch (e) { // Log.d(❌ 获取定位失败: $e); if (mounted) { setState(() { _currentAddress 获取位置失败请检查GPS设置; }); } } finally { if (mounted) { setState(() { _isLoadingLocation false; }); } } } //经纬度转地址 Futurevoid _getAddressFromLatLng(double latitude, double longitude) async { try { //地址解析 ListPlacemark placemarks await placemarkFromCoordinates( latitude, longitude, localeIdentifier: zh_CN, // 中文显示 ); if (placemarks.isNotEmpty mounted) { Placemark place placemarks[0]; // 构建详细地址 ListString addressParts []; // //国家 // if (place.country ! null place.country!.isNotEmpty) { // addressParts.add(place.country!); // } //省份 // if (place.administrativeArea ! null place.administrativeArea!.isNotEmpty) { // Log.d(⭐administrativeArea当前得到的值为${place.administrativeArea!}); // addressParts.add(place.administrativeArea!); // } // //城市 // if (place.locality ! null place.locality!.isNotEmpty) { // Log.d(⭐locality当前得到的值为${place.locality!}); // addressParts.add(place.locality!); // } // //区县 // if (place.subLocality ! null place.subLocality!.isNotEmpty) { // Log.d(⭐subLocality当前得到的值为${place.subLocality!}); // addressParts.add(place.subLocality!); // } //街道 if (place.street ! null place.street!.isNotEmpty) { // Log.d(⭐street当前得到的值为${place.street!}); addressParts.add(place.street!); } String fullAddress addressParts.join( ); // 如果地址为空使用经纬度 if (fullAddress.isEmpty) { fullAddress 纬度: $latitude, 经度: $longitude; } setState(() { _currentAddress fullAddress; _isLoadingLocation false; }); // Log.d( 当前地址: $fullAddress); // 如果需要上传到服务器在这里调用 // await YourHttpService.uploadLocation(latitude, longitude, fullAddress); } } catch (e) { // Log.d(❌ 获取地址失败: $e); if (mounted) { setState(() { _currentAddress 获取地址失败 (经纬度: $latitude, $longitude); _isLoadingLocation false; }); } } } override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0xFFF5FCFF), appBar: AppBar( backgroundColor: Color(0xFFF5FCFF), leading: IconButton( onPressed: () { Navigator.pop(context); }, icon: Icon(Icons.arrow_back_ios), ), title: Text( findDevice, style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold), ), centerTitle: true, ), body: Container( width: double.infinity, height: double.infinity, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFF5FCFF), Color(0xFFF2F4F5), ], ), ), child: Column( children: [ SizedBox(height: 10), // 查找容器 _buildFindContainer(), SizedBox(height: 40), // 详细地址显示定位信息 _buildAddress(), ], ), ), ); } // 查找容器 Widget _buildFindContainer() { return Container( width: double.infinity, height: 352, margin: EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(40), gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFCFFFF5), Color(0xFFFFFFFF), ], ), boxShadow: [ BoxShadow( color: Color(0xFF000000).withOpacity(0.1), offset: Offset(3, 0), spreadRadius: 3, blurRadius: 5, ), ], ), child: Column( children: [ SizedBox(height: 20), // 产品图 Container( width: 150, height: 150, decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFF777777).withOpacity(0.3), border: Border.all( color: Color(0xFF777777).withOpacity(0.2), width: 20, ), ), child: Center( child: Text(产品图), ), ), SizedBox(height: 50), // 响铃按钮 GestureDetector( onTap: () { // 点击时触发响铃 // Log.d(点击唤醒设备); }, child: Container( height: 52, width: 129, decoration: BoxDecoration( borderRadius: BorderRadius.circular(26), color: Color(0xFF4AC6AD), boxShadow: [ BoxShadow( color: Color(0xFF000000).withOpacity(0.1), offset: Offset(3, 0), spreadRadius: 3, blurRadius: 5, ), ], ), child: Center( child: Text( tapRing, style: TextStyle(color: Colors.white, fontSize: 18), ), ), ), ), Spacer(), // 温馨提示 Text( *$tapRingTips*, style: TextStyle(color: Color(0xFF3D3D3D), fontSize: 12), ), SizedBox(height: 20), ], ), ); } // 详细地址 Widget _buildAddress() { return Container( width: double.infinity, height: 196, margin: EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(31), color: Colors.white, boxShadow: [ BoxShadow( color: Color(0xFF000000).withOpacity(0.1), offset: Offset(3, 0), spreadRadius: 3, blurRadius: 5, ), ], ), child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ //地址行 Row( children: [ //地址 Expanded(child: Text(_currentAddress,style: TextStyle(fontSize: 15,color: Color(0xFF3D3D3D)),)), //定位按钮 IconButton( onPressed: (){ showBottomSheetDialog(context); }, icon: Icon(Icons.navigation), ) ], ), //分割线 Container( height: 1, width: double.infinity, color: Colors.black.withOpacity(0.1), ), Spacer(), //温馨提示 Text( *$addressTips*, style: TextStyle(color: Color(0xFF3D3D3D), fontSize: 12), ), SizedBox(height: 5,), ], ), ), ); } //导航弹窗 void showBottomSheetDialog(BuildContext context){ showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)) ), builder: (BuildContext context){ return Container( padding: EdgeInsets.symmetric( vertical: 20, //horizontal: 10 ), height: 250, child: Column( children: [ GestureDetector( onTap: () async { goGaodeMap(); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFF4AC6AD).withOpacity(0.8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(高德地图,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), SizedBox(height: 5,), GestureDetector( onTap: (){ //跳转百度地图 goBaiduMap(); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFF4AC6AD).withOpacity(0.8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(百度地图,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), SizedBox(height: 25,), Container( height: 1, width: double.infinity, color: Color(0xFFA8A8A8), ), SizedBox(height: 15,), GestureDetector( onTap: (){ Navigator.pop(context); }, child: Container( width: 325, height: 52, decoration: BoxDecoration( color: Color(0xFFA8A8A8), borderRadius: BorderRadius.circular(10) ), child: Center( child: Text(取消,style: TextStyle(color:Colors.white,fontSize: 18),), ), ), ), ], ), ); } ); } ///跳转高德地图 Futurevoid goGaodeMap() async{ try { if (_currentPosition null) { Fluttertoast.showToast(msg: 请先获取当前位置); return; } // 检查高德地图是否安装 bool isAmapAvailable await map_launcher.MapLauncher.isMapAvailable(map_launcher.MapType.amap); if (isAmapAvailable) { print(高德地图已安装准备跳转); if (_currentAddress ! null) { await map_launcher.MapLauncher.showMarker( mapType: map_launcher.MapType.amap, coords: map_launcher.Coords( _currentPosition!.latitude, _currentPosition!.longitude ), title: , // 使用设备名称 description: 耳机位置, // 可选描述 ); print(跳转成功); } else { print(无法获取耳机位置); Fluttertoast.showToast(msg: 无法获取耳机位置); } } else { print(高德地图未安装); Fluttertoast.showToast(msg: 请先安装高德地图); } } catch (e) { print(跳转失败: $e); Fluttertoast.showToast(msg: 跳转失败); } Navigator.pop(context); } ///跳转百度地图 Futurevoid goBaiduMap() async{ try { if (_currentPosition null) { Fluttertoast.showToast(msg: 请先获取当前位置); return; } // 检查百度地图是否安装 bool isBaiduAvailable await map_launcher.MapLauncher.isMapAvailable(map_launcher.MapType.baidu); if (isBaiduAvailable) { print(高德地图已安装准备跳转); //耳机的位置 if (_currentAddress ! null) { await map_launcher.MapLauncher.showMarker( mapType: map_launcher.MapType.baidu, coords: map_launcher.Coords( _currentPosition!.latitude, _currentPosition!.longitude ), title: , // 使用设备名称 description: 耳机位置, // 可选描述 ); print(跳转成功); } else { print(无法获取耳机位置); Fluttertoast.showToast(msg: 无法获取耳机位置); } } else { print(高德地图未安装); Fluttertoast.showToast(msg: 请先安装百度地图); } } catch (e) { print(跳转失败: $e); Fluttertoast.showToast(msg: 跳转失败); } Navigator.pop(context); } }
企业数字化 ERP 产品动态
相关推荐
没有开放集成与低代码,协同中台只是空谈 当 CIO 查看企业 IM 后台时,常会发现一个尴尬的事实:每天超过 90% 的业务消息都在讨论订单、审批、客户变更,但这些对话永远停留在聊天窗口里,无法直接驱动 ERP 审批流,也不能自动同步到 CRM 客户时间线。另一边&#… · 2026/8/4 9:19:40
一些感受与总结 prd对齐,那些情况要考虑,那些要做哪些不做trd评审,刚好为ai coding材料对齐,遇到问题多问,多和产品、研发和测试同学联系(终于知道以前为什么“明明是”这样却要拉一个会,明确哪些做哪些不做设计… · 2026/9/22 13:32:13
Unity热重载实战:5分钟配置,告别编译等待,实时调试代码 1. 项目概述:为什么我们需要热重载?如果你是一名Unity开发者,无论是刚入门的新手,还是摸爬滚打多年的老手,下面这个场景你一定不陌生:为了测试一个简单的数值调整,比如把跳跃高度从5改成6&#… · 2026/9/20 3:08:27
Hermes 与 DeepSeek 多智能体编排实战:部署、API Key 配置与调优 1. 先把 Hermes 和 DeepSeek 的关系理清楚很多人第一次看到 "hermes DeepSeek" 这个组合,脑子里第一反应是:这俩到底谁管谁?是 Hermes 调用 DeepSeek,还是 DeepSeek 里面跑 Hermes?我一开始也绕了半天&… · 2026/9/26 5:23:10
Canvas粒子弹簧模型:从像素采样到悬挂弹性文字特效 简介:HTML5 Canvas悬挂弹性文字特效是面向前端学习者与交互设计入门的实践范例,重点演示Canvas绘图API、鼠标事件与动画循环的配合用法,解决如何在网页中实现带物理弹性的动态文字问题。包内共4个文件,整体仅3KB,含一个… · 2026/9/26 5:23:04
基于Mininet与Ryu的SDN实验环境搭建与排错实践 最近在搭建SDN实验环境,把Mininet和Ryu控制器从零理顺了一遍。整个过程踩了不少坑,也把原理层面的事情想明白了一些。Mininet作为轻量级网络仿真工具,能在普通笔记本上模拟出一整张交换网络,配合Ryu这个OpenFlow控制器,… · 2026/9/26 5:23:04
Mininet+Ryu搭建SDN实验环境:从安装到流表下发全流程解析 最近两年软件定义网络这个话题在面试和实操里被反复提起,很多朋友一上来就纠结该用哪款模拟器、该配哪个控制器。我的建议很简单:如果你只是想快速把 SDN 的数据平面、控制平面、OpenFlow 协议这些东西跑通,Mininet 加 Ryu 是目前性价比最高的… · 2026/9/26 5:23:04
Flutter跨平台实战:鸿蒙二手交易App开发与适配全解析 做二手物品交易这个方向,我从去年就开始关注了。市面上大平台聚焦的是全品类、物流、支付和售后,流程很重,但在校园、社区这类熟人半径里,用户真正需要的其实是一个“发布、浏览、私聊、线下交易”的轻量工具。所以这个项目我起名… · 2026/9/26 5:23:04
GCC 9.5.0源码编译实战:彻底解决gcc/g++版本不对 简介:gcc-9.5.0.tar.gz是GNU编译器集合9.5.0版本的完整源码压缩包,面向Linux/Unix系统开发者、编译器研究者和需要从源码构建GCC环境的用户。包内主要包含C、C、Objective-C、Fortran等语言前端与后端实现,以及configure配置脚本、构建和安装… · 2026/9/26 5:23:04
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46