Flutter---GPS定位(2)

Flutter---GPS定位(2) 功能跳转主流地图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); } }