You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:57:00