android - Flutter iOS - 在加载谷歌地图小部件之前无法获取 initialCameraPosition 的当前位置

标签 android ios google-maps flutter location

我正在尝试在我的 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/

相关文章:

android - 检查是否在 Android 应用程序中启用了同步

android - 模拟器因 TextView 和 ImageView 而崩溃

ios - 如何从动态创建的 Storyboard属性为 nil 的 UIViewController 中执行 SegueWithIdentifier()

javascript - 如何打开 map Activity 并从另一个 Activity 设置位置?

java - 跟踪 GPS 位置 - 实时反馈

AndroidRuntime android.database.SQLiteException : near "=": syntax error

java - 写入应该关闭的 java 套接字 channel 不会产生异常

ios - Game Center成就每次都有奖励

ios - Swift Core Data 多对多关系处理,代码生成为手动/无

javascript - 谷歌地图视差效果