Flutter中如何实现经纬度转地址、统计打卡时长并存储到Firebase
功能实现修复方案
1. 经纬度转地址功能修复
你已经导入了geocoding包,只需要在获取到定位数据后调用地址转换接口,拼接出完整地址后同步存入Firestore即可,修改_getLocation方法如下:
Future<void> _getLocation() async { // 先检查定位权限,确认授权后再监听 var status = await Permission.location.request(); if (!status.isGranted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("请先授予定位权限"))); return; } _locationSubscription = location.onLocationChanged.handleError((onError) { print(onError); _locationSubscription?.cancel(); setState(() { _locationSubscription = null; }); }).listen((loc.LocationData currentLocation) async { // 新增经纬度转地址逻辑 List<Placemark> placemarks = await placemarkFromCoordinates( currentLocation.latitude!, currentLocation.longitude!, ); String address = "未知地址"; if (placemarks.isNotEmpty) { Placemark p = placemarks.first; address = "${p.street ?? ""} ${p.subLocality ?? ""} ${p.locality ?? ""} ${p.administrativeArea ?? ""} ${p.postalCode ?? ""}"; address = address.trim(); } // 修复原代码写死文档id为user1的问题,改为用当前用户uid避免多用户数据覆盖 await FirebaseFirestore.instance.collection('location').doc(user!.uid).set({ 'latitude': currentLocation.latitude, 'longitude': currentLocation.longitude, 'name': '${loggedInUser.name}', 'address': address, // 新增地址字段存入Firestore }, SetOptions(merge: true)); }); }
之后修改列表展示部分,在UI中显示转换后的地址:
// 原ListTile的subtitle部分修改为以下代码 subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text(snapshot.data!.docs[index]['latitude'].toString()), const SizedBox(width: 20), Text(snapshot.data!.docs[index]['longitude'].toString()), ], ), const SizedBox(height: 4), Text(snapshot.data!.docs[index]['address'] ?? "地址加载中"), ], ),
2. 签到、签退与停留时长实现
第一步:新增状态变量
在_HomeScreenState类中新增以下变量:
DateTime? _checkInTime; bool _isCheckedIn = false;
第二步:新增签到签退按钮
在原Stop Live Location按钮下方新增两个按钮:
TextButton( onPressed: _isCheckedIn || _locationSubscription == null ? null : () async { setState(() { _checkInTime = DateTime.now(); _isCheckedIn = true; }); // 签到时间存入Firestore,用服务器时间避免本地时间不准 await FirebaseFirestore.instance.collection('location').doc(user!.uid).set({ 'checkInTime': FieldValue.serverTimestamp(), }, SetOptions(merge: true)); }, child: Text(_isCheckedIn ? "已签到" : "签到"), ), TextButton( onPressed: !_isCheckedIn ? null : () async { final checkOutTime = DateTime.now(); final stayDuration = checkOutTime.difference(_checkInTime!); setState(() { _isCheckedIn = false; }); // 签退时间和停留时长存入Firestore,时长存为分钟数方便后续统计 await FirebaseFirestore.instance.collection('location').doc(user!.uid).set({ 'checkOutTime': FieldValue.serverTimestamp(), 'stayDurationMinutes': stayDuration.inMinutes, }, SetOptions(merge: true)); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("本次停留时长:${stayDuration.inMinutes}分钟")) ); }, child: const Text("签退"), ),
3. 前置配置检查
- 确认
pubspec.yaml中已添加兼容版本依赖:dependencies: geocoding: ^2.1.0 location: ^4.4.0 permission_handler: ^10.2.0 - 安卓端在
android/app/src/main/AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> - iOS端在
ios/Runner/Info.plist中添加权限说明:<key>NSLocationWhenInUseUsageDescription</key> <string>需要获取您的位置来实现定位签到功能</string>
内容的提问来源于stack exchange,提问作者stormm
相关产品推荐
相关产品推荐

