我从Cloud Firestore中的数据库查询地理位置数据时遇到问题。我浏览了Youtube上的文档后得出结论,当我将地理位置数据保存在子集合中时,它对我来说最有效。
这是我的数据库结构:
如果您进入子集合中的文档之一:
数据库本身有一个名为“ tourguides”的集合,每个文档都包含基本信息,例如游览名称和游览所在的区域(均为字符串)。然后,每个文档都有一个称为“位置”的子集合,其中每个文档都具有字符串“名称”和“ ID”,以及一个包含纬度和经度数据的地理位置。 ListView中显示了“ Tourguides”集合中的文档。每当我点击其中一个条目时,都会打开一个地图,其中显示了各个子集合中的所有标记。
这是我的ListView Builder:
@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文档显示,如果我从数据库中删除这些集合,则必须始终引用特定的文档。
例如(集合/文档/集合)。但是在我的查询中,路径中间的“文档”始终是不同的,具体取决于用户单击哪个导游。
有什么想法吗?期待您的回复!
更新:我稍微配置了数据库结构!我现在使用两个独立的数据库。一个数据库保存有关可用导游的信息(当前只有两个字符串:Name和Region),另一个数据库存储实际的各个位置。 现在,我根据查询所属的向导的名称,使用where-query获取正确的位置。
查询本身现在可以在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中的条目之一,则将正确的条目打印到控制台中。但是我需要弹出一个Google Map,以根据数据库中的“地理位置”值显示适当的标记。
答案 0 :(得分:0)
兄弟,我做到了。我可以通过两种方式检索它。 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,
)
],
)
],
));
}
}
答案 1 :(得分:0)
这是使用提供程序的第二种方法。
首先,您必须确定模型(只关注“ 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'];
}
}
秒,为其提供提供商:
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服务中添加“获取”:
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,
)
],
)
],
));
}
}