Flutter Google 地图 - 将相机移动到当前位置
Flutter Google Maps - Move camera to current position
在我的 Flutter 项目中,我使用 Google 地图插件在应用程序中显示地图。在地图上,我想显示用户的当前位置,为此我使用了 Geolocator。
当地图加载时,它将加载到一个静态点上,当用户拒绝位置权限时,用户仍然可以在没有位置的情况下使用地图。当用户接受权限时,我想将相机移动到用户当前位置。
我已经在下面的代码中实现了上面的代码,但我也遇到了以下错误,我不知道如何解决它。
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'dart:typed_data';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hvd_test/styling/colors.dart';
import 'package:hvd_test/models/navigation.dart';
import 'package:hvd_test/models/markers.dart';
// This page shows a Google Map plugin with all stations (HvD and Total). The markers are pulled from a Firebase database.
class StationsMap extends StatefulWidget {
@override
_StationsMap createState() => _StationsMap();
}
class _StationsMap extends State<StationsMap> {
bool _isLocationGranted = false;
var currentLocation;
GoogleMapController mapController;
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
// Below function initiates all HvD stations and shows them as markers on the map. It also generates a Bottom Sheet for each location with corresponding information.
void initMarkerHvD(specify, specifyId) async {
var markerIdVal = specifyId;
final Uint8List markerHvD =
await getBytesFromAsset('images/Pin-HvD.JPG', 70);
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
specify['stationName'],
style: TextStyle(
color: PaletteBlue.hvdblue,
fontWeight: FontWeight.bold,
fontSize: 16),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
Text(specify['stationAddress']),
Text(specify['stationZIP'] +
' ' +
specify['stationCity']),
SizedBox(height: 20),
ElevatedButton(
child: Text(
'Navigeer naar locatie',
style: TextStyle(
color: Colors.white,
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
PaletteOrange.hvdorange)),
onPressed: () {
MapUtils.openMap(
specify['stationLocation'].latitude,
specify['stationLocation'].longitude);
}),
],
),
),
),
),
));
},
position: LatLng(specify['stationLocation'].latitude,
specify['stationLocation'].longitude),
infoWindow: InfoWindow(),
icon: BitmapDescriptor.fromBytes(markerHvD),
);
setState(() {
markers[markerId] = marker;
});
}
// Below function initiates all Total stations and shows them as markers on the map. It also generates a Bottom Sheet for each location with corresponding information.
void initMarkerTotal(specify, specifyId) async {
var markerIdVal = specifyId;
final Uint8List markerTotal =
await getBytesFromAsset('images/Pin-Total.JPG', 70);
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
specify['stationName'],
style: TextStyle(
color: PaletteBlue.hvdblue,
fontWeight: FontWeight.bold,
fontSize: 16),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
Text(specify['stationAddress']),
Text(specify['stationZIP'] +
' ' +
specify['stationCity']),
SizedBox(height: 20),
ElevatedButton(
child: Text(
'Navigeer naar locatie',
style: TextStyle(
color: Colors.white,
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
PaletteOrange.hvdorange)),
onPressed: () {
MapUtils.openMap(
specify['stationLocation'].latitude,
specify['stationLocation'].longitude);
}),
],
),
),
),
),
));
},
position: LatLng(specify['stationLocation'].latitude,
specify['stationLocation'].longitude),
infoWindow: InfoWindow(),
icon: BitmapDescriptor.fromBytes(markerTotal),
);
setState(() {
markers[markerId] = marker;
});
}
// Below functions pulls all HvD markers from the database.
getMarkerDataHvD() async {
FirebaseFirestore.instance
.collection('hvd-stations')
.get()
.then((myMarkers) {
if (myMarkers.docs.isNotEmpty) {
for (int i = 0; i < myMarkers.docs.length; i++) {
initMarkerHvD(myMarkers.docs[i].data(), myMarkers.docs[i].id);
}
}
});
}
// Below function pulls all Total markers from the database.
getMarkerDataTotal() async {
FirebaseFirestore.instance
.collection('total-stations')
.get()
.then((myMarkers) {
if (myMarkers.docs.isNotEmpty) {
for (int i = 0; i < myMarkers.docs.length; i++) {
initMarkerTotal(myMarkers.docs[i].data(), myMarkers.docs[i].id);
}
}
});
}
// Below function initiates all previous functions on the page. This happens when the user navigates to the page.
void initState() {
getMarkerDataHvD();
getMarkerDataTotal();
super.initState();
Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.then((currloc) {
setState(() {
currentLocation = currloc;
_isLocationGranted = true;
});
mapController.moveCamera(CameraUpdate.newLatLng(LatLng(currentLocation.latitude, currentLocation.longitude))) as CameraPosition;
});
}
CameraPosition _initialCameraPosition =
CameraPosition(target: const LatLng(51.9244201, 4.4777325), zoom: 12);
// Below function is used to display all previous functions to the page.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(
children: <Widget>[
GoogleMap(
onMapCreated: onMapCreated,
markers: Set<Marker>.of(markers.values),
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>[
new Factory<OneSequenceGestureRecognizer>(
() => new EagerGestureRecognizer(),
),
].toSet(),
mapToolbarEnabled: false,
zoomGesturesEnabled: true,
zoomControlsEnabled: false,
scrollGesturesEnabled: true,
myLocationEnabled: _isLocationGranted,
myLocationButtonEnabled: true,
initialCameraPosition: _initialCameraPosition,
),
],
),
),
);
}
onMapCreated(GoogleMapController controller) {
mapController = controller;
}
}
我得到的错误是这样的:
E/flutter ( 7769): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'Future<void>' is not a subtype of type 'CameraPosition' in type cast
E/flutter ( 7769): #0 _StationsMap.initState.<anonymous closure>
E/flutter ( 7769): #1 _rootRunUnary (dart:async/zone.dart:1362:47)
E/flutter ( 7769): #2 _CustomZone.runUnary (dart:async/zone.dart:1265:19)
E/flutter ( 7769): <asynchronous suspension>
有人可以给我一些帮助吗?
感谢@Andy,我解决了这个问题。我从代码中删除了“as CameraPosition”,然后该功能起作用了。我还通过使用实现了缩放:
mapController.animateCamera(CameraUpdate.newLatLngZoom(LatLng(currentLocation.latitude, currentLocation.longitude), 14));
在我的 Flutter 项目中,我使用 Google 地图插件在应用程序中显示地图。在地图上,我想显示用户的当前位置,为此我使用了 Geolocator。
当地图加载时,它将加载到一个静态点上,当用户拒绝位置权限时,用户仍然可以在没有位置的情况下使用地图。当用户接受权限时,我想将相机移动到用户当前位置。
我已经在下面的代码中实现了上面的代码,但我也遇到了以下错误,我不知道如何解决它。
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'dart:typed_data';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hvd_test/styling/colors.dart';
import 'package:hvd_test/models/navigation.dart';
import 'package:hvd_test/models/markers.dart';
// This page shows a Google Map plugin with all stations (HvD and Total). The markers are pulled from a Firebase database.
class StationsMap extends StatefulWidget {
@override
_StationsMap createState() => _StationsMap();
}
class _StationsMap extends State<StationsMap> {
bool _isLocationGranted = false;
var currentLocation;
GoogleMapController mapController;
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
// Below function initiates all HvD stations and shows them as markers on the map. It also generates a Bottom Sheet for each location with corresponding information.
void initMarkerHvD(specify, specifyId) async {
var markerIdVal = specifyId;
final Uint8List markerHvD =
await getBytesFromAsset('images/Pin-HvD.JPG', 70);
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
specify['stationName'],
style: TextStyle(
color: PaletteBlue.hvdblue,
fontWeight: FontWeight.bold,
fontSize: 16),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
Text(specify['stationAddress']),
Text(specify['stationZIP'] +
' ' +
specify['stationCity']),
SizedBox(height: 20),
ElevatedButton(
child: Text(
'Navigeer naar locatie',
style: TextStyle(
color: Colors.white,
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
PaletteOrange.hvdorange)),
onPressed: () {
MapUtils.openMap(
specify['stationLocation'].latitude,
specify['stationLocation'].longitude);
}),
],
),
),
),
),
));
},
position: LatLng(specify['stationLocation'].latitude,
specify['stationLocation'].longitude),
infoWindow: InfoWindow(),
icon: BitmapDescriptor.fromBytes(markerHvD),
);
setState(() {
markers[markerId] = marker;
});
}
// Below function initiates all Total stations and shows them as markers on the map. It also generates a Bottom Sheet for each location with corresponding information.
void initMarkerTotal(specify, specifyId) async {
var markerIdVal = specifyId;
final Uint8List markerTotal =
await getBytesFromAsset('images/Pin-Total.JPG', 70);
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
specify['stationName'],
style: TextStyle(
color: PaletteBlue.hvdblue,
fontWeight: FontWeight.bold,
fontSize: 16),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
Text(specify['stationAddress']),
Text(specify['stationZIP'] +
' ' +
specify['stationCity']),
SizedBox(height: 20),
ElevatedButton(
child: Text(
'Navigeer naar locatie',
style: TextStyle(
color: Colors.white,
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
PaletteOrange.hvdorange)),
onPressed: () {
MapUtils.openMap(
specify['stationLocation'].latitude,
specify['stationLocation'].longitude);
}),
],
),
),
),
),
));
},
position: LatLng(specify['stationLocation'].latitude,
specify['stationLocation'].longitude),
infoWindow: InfoWindow(),
icon: BitmapDescriptor.fromBytes(markerTotal),
);
setState(() {
markers[markerId] = marker;
});
}
// Below functions pulls all HvD markers from the database.
getMarkerDataHvD() async {
FirebaseFirestore.instance
.collection('hvd-stations')
.get()
.then((myMarkers) {
if (myMarkers.docs.isNotEmpty) {
for (int i = 0; i < myMarkers.docs.length; i++) {
initMarkerHvD(myMarkers.docs[i].data(), myMarkers.docs[i].id);
}
}
});
}
// Below function pulls all Total markers from the database.
getMarkerDataTotal() async {
FirebaseFirestore.instance
.collection('total-stations')
.get()
.then((myMarkers) {
if (myMarkers.docs.isNotEmpty) {
for (int i = 0; i < myMarkers.docs.length; i++) {
initMarkerTotal(myMarkers.docs[i].data(), myMarkers.docs[i].id);
}
}
});
}
// Below function initiates all previous functions on the page. This happens when the user navigates to the page.
void initState() {
getMarkerDataHvD();
getMarkerDataTotal();
super.initState();
Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.then((currloc) {
setState(() {
currentLocation = currloc;
_isLocationGranted = true;
});
mapController.moveCamera(CameraUpdate.newLatLng(LatLng(currentLocation.latitude, currentLocation.longitude))) as CameraPosition;
});
}
CameraPosition _initialCameraPosition =
CameraPosition(target: const LatLng(51.9244201, 4.4777325), zoom: 12);
// Below function is used to display all previous functions to the page.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(
children: <Widget>[
GoogleMap(
onMapCreated: onMapCreated,
markers: Set<Marker>.of(markers.values),
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>[
new Factory<OneSequenceGestureRecognizer>(
() => new EagerGestureRecognizer(),
),
].toSet(),
mapToolbarEnabled: false,
zoomGesturesEnabled: true,
zoomControlsEnabled: false,
scrollGesturesEnabled: true,
myLocationEnabled: _isLocationGranted,
myLocationButtonEnabled: true,
initialCameraPosition: _initialCameraPosition,
),
],
),
),
);
}
onMapCreated(GoogleMapController controller) {
mapController = controller;
}
}
我得到的错误是这样的:
E/flutter ( 7769): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'Future<void>' is not a subtype of type 'CameraPosition' in type cast
E/flutter ( 7769): #0 _StationsMap.initState.<anonymous closure>
E/flutter ( 7769): #1 _rootRunUnary (dart:async/zone.dart:1362:47)
E/flutter ( 7769): #2 _CustomZone.runUnary (dart:async/zone.dart:1265:19)
E/flutter ( 7769): <asynchronous suspension>
有人可以给我一些帮助吗?
感谢@Andy,我解决了这个问题。我从代码中删除了“as CameraPosition”,然后该功能起作用了。我还通过使用实现了缩放:
mapController.animateCamera(CameraUpdate.newLatLngZoom(LatLng(currentLocation.latitude, currentLocation.longitude), 14));