在地图上显示Firebase子集合的图钉-Flutter [英] Show pins of a subcollection of firebase on map - Flutter

查看:33
本文介绍了在地图上显示Firebase子集合的图钉-Flutter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,可以从火力地带读取停车数据,并在地图上显示一些图钉.现在,应用程序仅显示用于停车的销钉,但是我还想在地图上添加来自保存在地块"中的每个停车场的销钉.停车场集合的子集合.我该怎么办?

I have an application that reads parkings data from firebase and shows some pins of on map. Now the application shows just the pins for parkings but I also want to add on the map the pins from every single parking lot saved in the "lots" subcollection of the Parkings collection. How can I do that?

maps.dart:

maps.dart:

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

  
  final List<DocumentSnapshot> documents;
  final LatLng initialPosition;
  final Completer<GoogleMapController> _controller = Completer();

  static final CameraPosition _initialPosition = CameraPosition(
    target: LatLng(45.791789, 24.150390),
    zoom: 16,
  );


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GoogleMap(
        mapType: MapType.hybrid,
        initialCameraPosition: _initialPosition,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        myLocationEnabled: true,
        markers:documents.map((document) => new Marker(
                  markerId: MarkerId(document.get('name')),
                  position: LatLng(
                    document.get('location').latitude,
                    document.get('location').longitude,
                  ),
                  onTap: () => _changeMap(LatLng(
                    document.get('location').latitude,
                    document.get('location').longitude,
                  )),
                  infoWindow: InfoWindow(
                      title: document.get('name'),
                      snippet: document.get('numberOfLots')),
             icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueViolet)),
                )
            .toSet()
      ),
  floatingActionButton: FloatingActionButton(
        onPressed: _currentLocation,
        child: Icon(Icons.location_searching),
        backgroundColor: Colors.deepPurple[400],
      ),
    );
  }

推荐答案

document.collection("lots").document("DocumentId").get('location').latitude不起作用的原因是,您不应该将字段名称传递给get方法.同样在您的代码中,文档只是文档快照,因此您要做的就是获取该文档的ID,然后访问其子集合和子文档.

The reason why document.collection("lots").document("DocumentId").get('location').latitude is not working is because you shouldn't pass the field name to get method. also in your code, document is just a document snapshot so what you want to do is get that document's id, and then access its sub collection and sub documents.

您可以做的事情是这样的:

What you can do is something like this:

//The code below gets the document ids of the parking collection
//gets access the sub collection "lots" and gets all the documents inside it.
//and for every sub document, gets the data and prints the latitude of the location field
for (DocumentSnapshot document in documents){
    String documentId = document.documentId;
    DocumentReference parkingDocReference = 
    Firestore.instance.collection("Parkings").document(documentId);
    parkingDocReference.collection("lots")
    .get((QuerySnapshot subDocuments){
    List<DocumentSnapshot> subDocumentsSnapshots = subDocuments.documents;
    for (DocumentSnapshot subDoc in subDocumentsSnapshots){
         String subDocId = subDoc.documentId;
         parkingDocReference.collection("lots")
         .document(subDocId).get().then((DocumentSnapshot snapshot){ 
             print(snapshot.data["location"].latitude); //prints the latitude;
         }
  
     }
  });

}

get()将返回Future<DocumentSnapshot>,这就是我们在get()之后使用.then()的原因,以便该函数仅在检索到数据时运行

get() will return Future<DocumentSnapshot> and that's why we are using .then() after get() so that the function will only run when the data is retrieved

更新: 为了查看地图上的标记,我们将上面的代码放入了返回Future<List<Marker>>的函数中.返回结果后,可以调用setState并使用小部件树中的更新列表.

Update: In order to see the markers on the map, we put the code above in a function which returns Future<List<Marker>>. when the result is returned, you can call setState and use the updated list in your widget tree.

最好使用 async/await 代替then,因为它会强制程序首先从未来获得结果.

It's better to use async/await instead of then as it forces the program to get the result from the future first.

Future<List<Marker>> _createMarkersForLotsAndParkings() async{
   List<Marker> markersList = [];
   int markerId = 0;
   for (DocumentSnapshot document in widget.documents){
    // ignore: deprecated_member_use
    String documentId = document.documentID;
    DocumentReference parkingDocReference = 
    // ignore: deprecated_member_use
    Firestore.instance.collection("Parkings").document(documentId);
    DocumentSnapshot parkingDocRef = await parkingDocReference.get();
    markersList.add(Marker(
                  markerId: MarkerId(markerId.toString()),
                  position: LatLng(parkingDocRef.get('location').latitude,
                      parkingDocRef.get('location').longitude),
                  onTap: () => _changeMap(LatLng(
                      parkingDocRef.get('location').latitude,
                      parkingDocRef.get('location').longitude)),
                  infoWindow: InfoWindow(
                      title: document.get('name'),
                      snippet: document.get('numberOfLots')),
                  icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueYellow)),
            );
            markerId++;
    QuerySnapshot subDocuments = await parkingDocReference.collection("lots").get();
    // ignore: deprecated_member_use
    // ignore: deprecated_member_use
    List<DocumentSnapshot> subDocumentsSnapshots = subDocuments.documents;
    for (DocumentSnapshot subDoc in subDocumentsSnapshots){
         // ignore: deprecated_member_use
         String subDocId = subDoc.documentID;
         DocumentSnapshot snapshot = await parkingDocReference.collection("lots")
         // ignore: deprecated_member_use
         .document(subDocId).get();
            print(snapshot.get('location').latitude);

            markersList.add(
              Marker(
                  markerId:MarkerId(markerId.toString()),
                  position: LatLng(snapshot.get('location').latitude,
                      snapshot.get('location').longitude),
                  onTap: () => _changeMap(LatLng(
                      snapshot.get('location').latitude,
                      snapshot.get('location').longitude)),
                  infoWindow: InfoWindow(
                      title: document.get('name'),
                      snippet: document.get('numberOfLots')),
                  icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueViolet)),
            );
            markerId++;

     }

}
return Future.value(markersList);

}


我们在initState()中调用此函数.您需要将StoreMap转换为StatefullWidget才能调用setState并使用initState:

We call this function in initState(). You need to convert StoreMap to a StatefullWidget in order to be able to call setState and use initState:


@override
  void initState() {
    super.initState();
    _createMarkersForLots().then((List<Marker> lotsMarkers){
    setState((){
    markers = lotsMarkers; //rebuilds the screen with the lotsMarkers. make sure to use the markers in your widget tree to see the markers
  });
    
});
}

您的完整代码必须看起来像这样:

And your full code has to look something like this:

import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';

class StoreMap extends StatefulWidget {
  StoreMap({
    Key key,
    @required this.documents,
    @required this.initialPosition,
  }) : super(key: key);

  final List<DocumentSnapshot> documents;
  final LatLng initialPosition;
  static final CameraPosition _initialPosition = CameraPosition(
    target: LatLng(45.791789, 24.150390),
    zoom: 16,
  );


  @override
  _StoreMapState createState() => _StoreMapState();
}

class _StoreMapState extends State<StoreMap> {
  final Completer<GoogleMapController> _controller = Completer();


List<Marker> markers = [];
Future<List<Marker>> _createMarkersForLotsAndParkings() async{
   List<Marker> markersList = [];
   int markerId = 0;
   for (DocumentSnapshot document in widget.documents){
    // ignore: deprecated_member_use
    String documentId = document.documentID;
    DocumentReference parkingDocReference = 
    // ignore: deprecated_member_use
    Firestore.instance.collection("Parkings").document(documentId);
    DocumentSnapshot parkingDocRef = await parkingDocReference.get();
    markersList.add(Marker(
                  markerId: MarkerId(markerId.toString()),
                  position: LatLng(parkingDocRef.get('location').latitude,
                      parkingDocRef.get('location').longitude),
                  onTap: () => _changeMap(LatLng(
                      parkingDocRef.get('location').latitude,
                      parkingDocRef.get('location').longitude)),
                  infoWindow: InfoWindow(
                      title: document.get('name'),
                      snippet: document.get('numberOfLots')),
                  icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueYellow)),
            );
            markerId++;
    QuerySnapshot subDocuments = await parkingDocReference.collection("lots").get();
    // ignore: deprecated_member_use
    // ignore: deprecated_member_use
    List<DocumentSnapshot> subDocumentsSnapshots = subDocuments.documents;
    for (DocumentSnapshot subDoc in subDocumentsSnapshots){
         // ignore: deprecated_member_use
         String subDocId = subDoc.documentID;
         DocumentSnapshot snapshot = await parkingDocReference.collection("lots")
         // ignore: deprecated_member_use
         .document(subDocId).get();
            print(snapshot.get('location').latitude);

            markersList.add(
              Marker(
                  markerId:MarkerId(markerId.toString()),
                  position: LatLng(snapshot.get('location').latitude,
                      snapshot.get('location').longitude),
                  onTap: () => _changeMap(LatLng(
                      snapshot.get('location').latitude,
                      snapshot.get('location').longitude)),
                  infoWindow: InfoWindow(
                      title: document.get('name'),
                      snippet: document.get('numberOfLots')),
                  icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueViolet)),
            );
            markerId++;
  
     }

}
return Future.value(markersList);

}

@override
  void initState() {
    super.initState();
    _createMarkersForLotsAndParkings().then((List<Marker> lotsMarkers){
    setState((){
    markers = lotsMarkers; 
  });
    
});
}


  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GoogleMap(
        zoomGesturesEnabled: true,
        mapType: MapType.hybrid,
        initialCameraPosition: StoreMap._initialPosition,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        myLocationEnabled: true,
        markers: markers.toSet(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _currentLocation,
        child: Icon(Icons.location_searching),
        backgroundColor: Colors.deepPurple[400],
      ),
    );
  }

  void _currentLocation() async {
    final GoogleMapController controller = await _controller.future;
    LocationData currentLocation;
    var location = new Location();
    try {
      currentLocation = await location.getLocation();
    } on Exception {
      currentLocation = null;
    }

    controller.animateCamera(CameraUpdate.newCameraPosition(
      CameraPosition(
        bearing: 0,
        target: LatLng(currentLocation.latitude, currentLocation.longitude),
        zoom: 18.0,
      ),
    ));
  }

  _changeMap(LatLng position) async {
    final GoogleMapController controller = await _controller.future;

    controller.animateCamera(CameraUpdate.newCameraPosition(
      CameraPosition(
        bearing: 0,
        target: LatLng(position.latitude, position.longitude),
        zoom: 19.4,
      ),
    ));
  }
}


Google地图为具有相同ID的标记显示一个标记,这就是为什么我们使用markerId为每个标记赋予唯一的ID并查看所有标记的原因.

Google map shows one marker for the markers with the same Id so that's why we are using markerId to give each marker an unique id and see all the markers.

这篇关于在地图上显示Firebase子集合的图钉-Flutter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆