【问题标题】:How to store geolocation data in Flutter with Cloud Firestore如何使用 Cloud Firestore 在 Flutter 中存储地理位置数据
【发布时间】:2020-03-01 14:11:23
【问题描述】:

我在从 Cloud Firestore 中的数据库查询我的地理位置数据时遇到问题。我浏览了 Youtube 上的文档并得出结论,当我将地理位置数据保存在子集合中时,它最适合我。

这是我的数据库结构:

如果您进入子集合中的文档之一:

数据库本身有一个名为“tourguides”的集合,每个文档都包含基本信息,如旅游名称和旅游所在地区(两者都是字符串)。然后,每个文档都有一个称为“位置”的子集合,其中每个文档都有字符串“名称”和“ID”,还有一个带有纬度和经度数据的地理点。 “Tourguides”集合中的文档显示在 ListView 中。每当我点击其中一个条目时,都会打开一个地图,其中显示来自相应子集合的所有标记。

这是我的 ListView 生成器:

@override
void initState() {
super.initState();
_pointsofinterest =    Firestore.instance.collection('tourguides').document('sydney_downtown_guide').col  lection('locations').orderBy('name').snapshots();
super.initState();
  }

  @override
 Widget build(BuildContext context) {
return Scaffold(
  body: StreamBuilder<QuerySnapshot>(
    stream: _pointsofinterest,
    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
      if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
      switch (snapshot.connectionState) {
        case ConnectionState.waiting:
          return new Text('Loading...');
        default:
          return new ListView(
            children:
                snapshot.data.documents.map((DocumentSnapshot document) {
              return InkWell(
                child: new ListTile(
                  title: new Text(document['name']),
                  subtitle: new Text(document['region']),
                  onTap: () {
                    return TourMap(
                      documents: snapshot.data.documents,
                      initialPosition: const LatLng(-33.868210, 151.208391),
                      mapController: _mapController,
                    );
                  },
                ),
              );
            }).toList(),
          );
      }
    },
  ),
);
 }

我将地图放入 StatlessWidget(我不确定。也许这必须是 StatefulWidget?):

class TourMap extends StatelessWidget {
const TourMap({
Key key,
@required this.documents,
@required this.initialPosition,
@required this.mapController,
}) : super(key: key);

final List<DocumentSnapshot> documents;
final LatLng initialPosition;
final Completer<GoogleMapController> mapController;

@override
Widget build(BuildContext context) {
 return GoogleMap(
  initialCameraPosition: CameraPosition(
    target: initialPosition,
    zoom: 12,
  ),
  markers: documents
      .map((document) => Marker(
            markerId: MarkerId(document['placeId']),
            icon: BitmapDescriptor.defaultMarker,
            position: LatLng(
              document['geolocation'].latitude,
              document['geolocation'].longitude,
            ),
            infoWindow: InfoWindow(
              title: document['location_name'],
            ),
          ))
      .toSet(),
  onMapCreated: (mapController) {
    this.mapController.complete(mapController);
  },
);
   }}

现在我不知道如何在我的 OnTap 函数中设置查询。 Firestore 文档显示,如果我从数据库中查看集合,我总是必须参考特定文档。

例如 (collection/document/collecion)。但在我的查询中,路径中间的“文档”总是不同的,具体取决于用户点击的导游。

对此有什么想法吗?期待您的回复!

更新:我稍微配置了我的数据库结构!我现在使用两个单独的数据库。一个数据库保存有关可用导游的信息(目前只有两个字符串:名称和地区),另一个数据库存储实际的个人位置。 我现在使用 where-queries 根据他们所属的导游姓名获取正确的位置。

查询本身现在适用于 OnTap 函数:

 return new ListView(
            children:
                snapshot.data.documents.map((DocumentSnapshot document) {
              return InkWell(
                child: new ListTile(
                  title: new Text(document['name']),
                  subtitle: new Text(document['region']),
                  onTap: () {
                    Firestore.instance.collection('locations').where(
                          "toActivity",
                          isEqualTo: document['name'],
                        )
                        .snapshots()
                        .listen((data) =>
                        data.documents.forEach((doc) => print(doc["location_name"])));
                  },
                ),
              );
            }).toList(),
          );

数据库结构:

如果我点击 ListView 中的一个条目,则正确的条目会打印到控制台中。但我需要弹出一个谷歌地图,根据数据库中的“地理位置”值显示适当的标记。

【问题讨论】:

  • 这个问题有点宽泛,没有看到你的结构,很难回答。您还应该包含您尝试过的代码,以便我们可以看到思考过程是什么。请更新您的问题。
  • @Jay 谢谢你的回复。我不确定是否必须在我的地图小部件中设置新的 Firebase 连接。我目前无法访问我的子集合。
  • @Jay 我更新了我的代码和我的问题。我的方法现在有点不同了。也许这有助于一些事情。

标签: firebase google-maps flutter google-cloud-firestore


【解决方案1】:

兄弟,我做到了。我可以通过两种方式检索它。 1. 手动使用简单的“initState”。 2.第二次使用提供者(但使用第二种方法,我还没有成功显示标记)。希望能帮到你,虽然是很久以前的事了。这是我的使用“initState”:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:visitmalang/provider/aktivitas_provider.dart';
import 'package:visitmalang/ui/home/beranda/aktivitas/profil_agen_wisata.dart';

import 'package:visitmalang/ui/widget/textcustom.dart';

class MapAktivitas extends StatefulWidget {
  @override
  _MapAktivitasState createState() => _MapAktivitasState();
}

class _MapAktivitasState extends State<MapAktivitas> {
  Map<MarkerId, Marker> markers = <MarkerId, Marker>{};

  GoogleMapController mapController;

  bool mapToggle = false;
  bool geraiToggle = false;

  var currentLocation;
  var clients = [];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Geolocator().getCurrentPosition().then((lokasiSekarang) {
      setState(() {
        currentLocation = lokasiSekarang;
        mapToggle = true;
        populateClients();
      });
    });
  }

  populateClients() {
    clients = [];
    Firestore.instance.collection('trail').getDocuments().then((docs) {
      if (docs.documents.isNotEmpty) {
        setState(() {
          geraiToggle = true;
        });

        for (int i = 0; i < docs.documents.length; i++) {
          clients.add(docs.documents[i].data);
          initMarker(docs.documents[i].data, docs.documents[i].documentID);
        }
      }
    });
  }

  void initMarker(request, requestId) {
    var markerIdVal = requestId;
    final MarkerId markerId = MarkerId(markerIdVal);
    final Marker marker = Marker(
        markerId: markerId,
        position: LatLng(
            request['koordinat'].latitude, request['koordinat'].longitude),
        infoWindow: InfoWindow(title: request['nama']));
    setState(() {
      markers[markerId] = marker;
    });
  }

  Widget clientCard(client) {
    return Padding(
      padding: const EdgeInsets.only(left: 8.0, top: 8.0),
      child: InkWell(
          onTap: () {
            zoomInMarker(client);
          },
          child: Stack(
            alignment: FractionalOffset(0.5, 0.94),
            children: <Widget>[
              Material(
                elevation: 4.0,
                borderRadius: BorderRadius.circular(10.0),
                child: Container(
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10.0),
                    color: Colors.white,
                  ),
                  height: 108,
                  width: 200,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
//
                      ClipRRect(
                        borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(10.0),
                            bottomLeft: Radius.circular(10.0)),
                        child: Container(
                          width: 96,
                          height: 108,
                          child: Image.asset(
                            'assets/trail.png',
                            fit: BoxFit.cover,
                          ),
                        ),
                      ),
                      SizedBox(
                        width: 4,
                      ),
                      Stack(
                        alignment: FractionalOffset(0.5, 0.9),
                        children: <Widget>[
                          Container(
                            width: 100,
                            child: Padding(
                              padding: const EdgeInsets.only(top: 8.0),
                              child: Column(
                                children: <Widget>[
                                  Padding(
                                    padding: const EdgeInsets.symmetric(
                                        horizontal: 8.0),
                                    child: Container(
                                      alignment: Alignment.center,
                                      child: textCustom(client['nama'],
                                          Colors.black87, 14, 'Montserrat'),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                          ClipRRect(
                            borderRadius: BorderRadius.circular(10),
                            child: InkWell(
                              onTap: () => Navigator.of(context).push(
                                  CupertinoPageRoute(
                                      builder: (BuildContext context) =>
                                          ProfilAgenWisata(
                                            nama: client['nama'],
                                            deskripsi: client['deskripsi'],
                                            website: client['website'],
                                            email: client['email'],
                                            noTelepon: client['noTelepon'],
                                            whatsApp: client['whatsApp'],
                                            alamat: client['alamat'],
                                            fasilitas: client['fasilitas'],
                                          ))),
                              child: Container(
                                alignment: Alignment.center,
                                color: Color(0xFFDB5C48),
                                height: 40,
                                width: 88,
                                child: textCustom(
                                    'Detail', Colors.white, 14, 'Montserrat'),
                              ),
                            ),
                          )
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ],
          )),
    );
  }

  zoomInMarker(client) {
    mapController.animateCamera(
      CameraUpdate.newCameraPosition(
        CameraPosition(
            target: LatLng(
                client['koordinat'].latitude, client['koordinat'].longitude),
            zoom: 16.0,
            bearing: 19.0,
            tilt: 15.0),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
//    AktivitasNotifier aktivitasNotifier = Provider.of<AktivitasNotifier>(context);
    return Scaffold(
        appBar: AppBar(
          title: textCustom('Ngetrail', Colors.black87, 18, 'Montserrat'),
          centerTitle: true,
          elevation: 0.0,
          backgroundColor: Colors.transparent.withOpacity(0.0),
          leading: IconButton(
              icon: Icon(Icons.arrow_back_ios, color: Colors.black87),
          onPressed: (){Navigator.pop(context);},),
        ),
        body: Stack(
          children: <Widget>[
            Column(
              children: <Widget>[
                Container(
                  width: double.infinity,
                  height: MediaQuery.of(context).size.height - 80,
                  child: mapToggle
                      ? GoogleMap(
                          myLocationEnabled: true,
                          myLocationButtonEnabled: true,
                          markers: Set<Marker>.of(markers.values),
                          compassEnabled: false,
                          zoomControlsEnabled: false,
                          mapType: MapType.normal,
                          initialCameraPosition: CameraPosition(
                              target: LatLng(currentLocation.latitude,
                                  currentLocation.longitude),
                              zoom: 15),
                          onMapCreated: (controller) {
                            setState(() {
                              mapController = controller;
                            });
                          },
                        )
                      : Center(
                          child: textCustom(
                              'Loading...', Colors.black87, 20, 'Hind')),
                ),
              ],
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Container(
                  height: 140.0,
                  width: MediaQuery.of(context).size.width,
                  child: geraiToggle
                      ? ListView(
                          scrollDirection: Axis.horizontal,
                          padding: EdgeInsets.all(8.0),
                          children: clients.map((element) {
                            return clientCard(element);
                          }).toList(),
                        )
                      : Container(),
                ),
                SizedBox(
                  height: 56.0,
                )
              ],
            )
          ],
        ));
  }
}

【讨论】:

    【解决方案2】:

    这是第二种方法,通过使用提供程序。

    首先,您必须确定模型(只关注“koordinat”):

        class ModelAktivitas {
      String idAktivitas;
      var koordinat;
      String nama;
      String deskripsi;
      String alamat;
      String email;
      String noTelepon;
      String website;
      String gambarUtama;
      List galeri;
      List fasilitas;
    
      ModelAktivitas.fromMap(Map<String, dynamic> data) {
        idAktivitas = data['idAktivitas'];
        koordinat = data['koordinat'];
        nama = data['nama'];
        deskripsi = data['deskripsi'];
        noTelepon = data['nomorTelepon'];
        galeri = data['galeri'];
        fasilitas = data['fasilitas'];
        alamat = data['alamat'];
        email = data['alamat'];
        gambarUtama = data['gambarUtama'];
        website = data['website'];
      }
    }
    

    第二个,为它做provider:

    import 'dart:collection';
    import 'package:flutter/cupertino.dart';
    import 'package:visitmalang/models/aktivitas_model.dart';
    
    class AktivitasNotifier with ChangeNotifier {
      List<ModelAktivitas> _listAktivitas = [];
      ModelAktivitas _detailAktivitas;
    
      UnmodifiableListView<ModelAktivitas> get listAktivitas =>
          UnmodifiableListView(_listAktivitas);
    
      ModelAktivitas get detailAktivitas => _detailAktivitas;
    
      set listAktivitas(List<ModelAktivitas> listAktivitas) {
        _listAktivitas = listAktivitas;
        notifyListeners();
      }
    
      set detailAktivitas(ModelAktivitas aktivitas) {
        _detailAktivitas = aktivitas;
        notifyListeners();
      }
    }
    

    之后,从您的 Firestore 服务中添加“get”:

    getListAktivitas(AktivitasNotifier aktivitasNotifier) async {
      QuerySnapshot snapshot =
      await Firestore.instance.collection('trail').getDocuments();
    
      List<ModelAktivitas> _listAktivitas = [];
      snapshot.documents.forEach((doc) {
        ModelAktivitas modelAktivitas = ModelAktivitas.fromMap(doc.data);
        _listAktivitas.add(modelAktivitas);
      });
      aktivitasNotifier.listAktivitas = _listAktivitas;
    
    }
    

    然后,最后一步将其流式传输到您的 UI 代码:

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:geolocator/geolocator.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    import 'package:provider/provider.dart';
    import 'package:visitmalang/provider/aktivitas_provider.dart';
    import 'package:visitmalang/ui/home/beranda/aktivitas/profil_agen_wisata.dart';
    import 'package:visitmalang/ui/widget/textcustom.dart';
    import 'package:visitmalang/service/user_service.dart';
    
    class MapAktivitasTandingan extends StatefulWidget {
      @override
      _MapAktivitasTandinganState createState() => _MapAktivitasTandinganState();
    }
    
    class _MapAktivitasTandinganState extends State<MapAktivitasTandingan> {
      Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
      GoogleMapController mapController;
      bool mapToggle = false;
      bool geraiToggle = false;
      var currentLocation;
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        Geolocator().getCurrentPosition().then((lokasiSekarang) {
          setState(() {
            currentLocation = lokasiSekarang;
            mapToggle = true;
          });
        });
    
        AktivitasNotifier aktivitasNotifier =
            Provider.of<AktivitasNotifier>(context, listen: false);
        getListAktivitas(aktivitasNotifier);
      }
    
      @override
      Widget build(BuildContext context) {
        AktivitasNotifier aktivitasNotifier =
            Provider.of<AktivitasNotifier>(context);
        return Scaffold(
            appBar: AppBar(
              title: textCustom('Ngetrail', Colors.black87, 18, 'Montserrat'),
              centerTitle: true,
              elevation: 0.0,
              backgroundColor: Colors.transparent.withOpacity(0.0),
              leading: IconButton(
                icon: Icon(Icons.arrow_back_ios, color: Colors.black87),
                onPressed: () {
                  Navigator.pop(context);
                },
              ),
            ),
            body: Stack(
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Container(
                      width: double.infinity,
                      height: MediaQuery.of(context).size.height - 80,
                      child: mapToggle
                          ? GoogleMap(
                              myLocationEnabled: true,
                              myLocationButtonEnabled: true,
                              markers: {
    
                              },
                              compassEnabled: false,
                              zoomControlsEnabled: false,
                              mapType: MapType.normal,
                              initialCameraPosition: CameraPosition(
                                  target: LatLng(currentLocation.latitude,
                                      currentLocation.longitude),
                                  zoom: 15),
                              onMapCreated: (controller) {
                                setState(() {
                                  mapController = controller;
                                });
                              },
                            )
                          : Center(
                              child: textCustom(
                                  'Loading...', Colors.black87, 20, 'Hind')),
                    ),
                  ],
                ),
                Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: <Widget>[
                    Container(
                        height: 140.0,
                        width: MediaQuery.of(context).size.width,
                        child: ListView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: aktivitasNotifier.listAktivitas.length,
                          itemBuilder: (BuildContext context, int index) {
                            return Padding(
                              padding: const EdgeInsets.only(left: 8.0, top: 8.0),
                              child: InkWell(
                                  onTap: () {
                                    mapController.animateCamera(
                                      CameraUpdate.newCameraPosition(
                                        CameraPosition(
                                            target: LatLng(
                                                aktivitasNotifier
                                                    .listAktivitas[index]
                                                    .koordinat
                                                    .latitude,
                                                aktivitasNotifier
                                                    .listAktivitas[index]
                                                    .koordinat
                                                    .longitude),
                                            zoom: 16.0,
                                            bearing: 19.0,
                                            tilt: 15.0),
                                      ),
                                    );
                                  },
                                  child: Stack(
                                    alignment: FractionalOffset(0.5, 0.94),
                                    children: <Widget>[
                                      Material(
                                        elevation: 4.0,
                                        borderRadius: BorderRadius.circular(10.0),
                                        child: Container(
                                          decoration: BoxDecoration(
                                            borderRadius:
                                                BorderRadius.circular(10.0),
                                            color: Colors.white,
                                          ),
                                          height: 108,
                                          width: 200,
                                          child: Row(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.center,
                                            children: <Widget>[
    //
                                              ClipRRect(
                                                borderRadius: BorderRadius.only(
                                                    topLeft: Radius.circular(10.0),
                                                    bottomLeft:
                                                        Radius.circular(10.0)),
                                                child: Container(
                                                  width: 96,
                                                  height: 108,
                                                  child: Image.asset(
                                                    'assets/trail.png',
                                                    fit: BoxFit.cover,
                                                  ),
                                                ),
                                              ),
                                              SizedBox(
                                                width: 4,
                                              ),
                                              Stack(
                                                alignment:
                                                    FractionalOffset(0.5, 0.9),
                                                children: <Widget>[
                                                  Container(
                                                    width: 100,
                                                    child: Padding(
                                                      padding:
                                                          const EdgeInsets.only(
                                                              top: 8.0),
                                                      child: Column(
                                                        children: <Widget>[
                                                          Padding(
                                                            padding:
                                                                const EdgeInsets
                                                                        .symmetric(
                                                                    horizontal:
                                                                        8.0),
                                                            child: Container(
                                                              alignment:
                                                                  Alignment.center,
                                                              child: textCustom(
                                                                  aktivitasNotifier
                                                                      .listAktivitas[
                                                                          index]
                                                                      .nama,
                                                                  Colors.black87,
                                                                  14,
                                                                  'Montserrat'),
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    ),
                                                  ),
                                                  ClipRRect(
                                                    borderRadius:
                                                        BorderRadius.circular(10),
                                                    child: InkWell(
                                                      onTap: () => Navigator.of(
                                                              context)
                                                          .push(CupertinoPageRoute(
                                                              builder: (BuildContext
                                                                      context) =>
                                                                  ProfilAgenWisata(
                                                                    nama: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .nama,
                                                                    website: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .website,
                                                                    noTelepon: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .noTelepon,
                                                                    email: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .email,
                                                                    alamat: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .alamat,
                                                                    deskripsi: aktivitasNotifier
                                                                        .listAktivitas[
                                                                            index]
                                                                        .deskripsi,
    
                                                                  ))),
                                                      child: Container(
                                                        alignment: Alignment.center,
                                                        color: Color(0xFFDB5C48),
                                                        height: 40,
                                                        width: 88,
                                                        child: textCustom(
                                                            'Detail',
                                                            Colors.white,
                                                            14,
                                                            'Montserrat'),
                                                      ),
                                                    ),
                                                  )
                                                ],
                                              ),
                                            ],
                                          ),
                                        ),
                                      ),
                                    ],
                                  )),
                            );
                          },
                        )),
                    SizedBox(
                      height: 56.0,
                    )
                  ],
                )
              ],
            ));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-08-27
      • 2022-11-07
      • 2012-04-03
      • 2020-11-27
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      相关资源
      最近更新 更多