我正在尝试在我的 Flutter iOS 应用程序中实现一个简单的 map 功能。我遵循了从 Flutter location package readme 开始的指南, 通过 Medium "Implement Real-time Location Updates on Google Maps in your Flutter Apps" article ,以关于类似问题的许多堆栈问题结束。
问题是我无法在加载 map 之前获取当前位置,因此在 initialCameraPosition
中获取其 LatLng 会导致 NPE。我能做的是使用硬编码的 initialCameraPosition
加载 map ,然后正确加载当前位置,然后我可以通过拖动或单击右下角的 float 位置按钮将相机移动到它。
这是我的代码示例:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
const double CAMERA_ZOOM = 16;
const LatLng SOURCE_LOCATION = LatLng(37.3317, -122.0325086);
class MapPage extends StatefulWidget {
@override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
GoogleMapController mapController;
LocationData currentLocation;
Location location;
bool _serviceEnabled;
PermissionStatus _permissionGranted;
@override
void initState() {
super.initState();
location = new Location();
location.onLocationChanged.listen((event) {
currentLocation = event;
});
setInitialLocation();
}
void setInitialLocation() async {
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return;
}
}
currentLocation = await location.getLocation();
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
CameraPosition initialCameraPosition() {
LatLng target;
if (currentLocation != null)
target = LatLng(currentLocation.latitude, currentLocation.longitude);
else
target = SOURCE_LOCATION;
return CameraPosition(target: target, zoom: CAMERA_ZOOM);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orangeAccent,
title: Text('Map'),
centerTitle: true,
),
body:
GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialCameraPosition(),
myLocationEnabled: true,
),
);
}
}
我明白获取当前位置是一个异步过程,所以我也尝试在正文部分使用FutureBuilder
:
FutureBuilder<LocationData>(
future: currentLocation,
builder: (context, snapshot) {
if (snapshot.hasData) {
LocationData currentLocation = snapshot.data;
return GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: LatLng(
currentLocation.latitude, currentLocation.longitude)),
myLocationEnabled: true,
);
} else if (snapshot.hasError) {
return (Text("${snapshot.error}"));
}
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.orangeAccent,
),
);
},
),
当我不得不从 http GET 请求中检索数据时,它的效果非常好,但这次它只会导致无休止的 CircularProgressIndicator
。
我从堆栈问题中尝试了许多其他解决方案,包括当 currentLocation
为 null 时返回空的 Container
,为 FutureBuilder snapshot.connectionState
创建条件,再次没有成功。
有趣的是,当我深入研究 Location.getCurrentLocation()
方法时,我发现:
/// Gets the current location of the user.
///
/// Throws an error if the app has no permission to access location.
/// Returns a [LocationData] object.
Future<LocationData> getLocation() async {
return LocationPlatform.instance.getLocation();
}
然后转到:
/// Gets the current location of the user.
///
/// Throws an error if the app has no permission to access location.
/// Returns a [LocationData] object.
Future<LocationData> getLocation() {
throw UnimplementedError();
}
这让我怀疑这个插件是否能正常工作。
这是我的 flutter doctor -v
结果:
[✓] Flutter (Channel master, v1.18.0-6.0.pre.82, on Mac OS X 10.15.4 19E287, locale pl-PL)
• Flutter version 1.18.0-6.0.pre.82 at /Users/Vuco/flutter
• Framework revision f35b673f2b (26 hours ago), 2020-04-19 02:45:01 +0530
• Engine revision a5e0b2f2f2
• Dart version 2.9.0 (build 2.9.0-1.0.dev 5b19445d9c)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
• Android SDK at /Users/Vuco/Library/Android/sdk
• Platform android-29, build-tools 29.0.3
• Java binary at: /Users/Vuco/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/192.6308749/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b4-5784211)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 11.4.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.4.1, Build version 11E503a
• CocoaPods version 1.9.1
[✓] Android Studio (version 3.6)
• Android Studio at /Users/Vuco/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/192.6308749/Android Studio.app/Contents
• Flutter plugin version 45.0.1
• Dart plugin version 192.7761
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b4-5784211)
[!] IntelliJ IDEA Ultimate Edition (version 2020.1)
• IntelliJ at /Users/Vuco/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
• For information about installing plugins, see
https://flutter.dev/intellij-setup/#installing-the-plugins
[✓] VS Code (version 1.44.0)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.9.1
[✓] Connected device (1 available)
• iPhone 8 • F60856B8-2C6E-401D-A0F9-06FFC7E09876 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-4 (simulator)
! Doctor found issues in 1 category.
以及我使用的依赖项:
google_maps_flutter: ^0.5.25+3
location: ^3.0.2
最佳答案
您在获得初始位置之前渲染 map 的问题,我相信您意识到这个 FutureBuilder
可以工作,但可能会被杀死。您真正需要的只是一个 bool 值。
GoogleMapController mapController;
LocationData currentLocation;
Location location;
bool _serviceEnabled;
PermissionStatus _permissionGranted;
CameraPosition _center =
CameraPosition(target: SOURCE_LOCATION, zoom: CAMERA_ZOOM);
bool isLoading = false;
@override
void initState() {
super.initState();
location = new Location();
_getLocation();
}
_getLocation() async {
setState(() {
isLoading = true;
});
initialize();
currentLocation = await location.getLocation();
if (currentLocation == null) {
return;
}
_center = CameraPosition(
target: LatLng(currentLocation.latitude, currentLocation.longitude),
zoom: CAMERA_ZOOM);
setState(() {
isLoading = false;
});
print("CurrentLocation: $currentLocation");
}
Future<void> initialize() async {
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.DENIED) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.GRANTED) {
return;
}
}
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orangeAccent,
title: Text('Map'),
centerTitle: true,
),
body: isLoading
? CircularProgressIndicator()
: Container(
child: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: _center,
myLocationEnabled: true,
),
),
);
}
关于android - Flutter iOS - 在加载谷歌地图小部件之前无法获取 initialCameraPosition 的当前位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61312809/