簡體   English   中英

在 flutter 中使用谷歌地圖移動和 web

[英]Using Google Maps in flutter for both mobile and web

我正在開發一個 flutter 應用程序,該應用程序應該具有 web 和移動設備的通用代碼庫。

我的應用程序將有一個谷歌 map,據我所知,沒有一個 package 可以滿足所有平台。

google_maps_flutter - seems to work only for mobile (IOS / Android)
google_maps_flutter_web - seems to work only for web

所以很可能我必須創建兩個單獨的 MapWidgets,一個用於 web,另一個用於使用這些單獨包的移動設備。

對於手機:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class MapSample extends StatefulWidget {
  MapSample({Key? key}) : super(key: key);

  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  final Completer<GoogleMapController> _controller = Completer();

  static const CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  @override
  Widget build(BuildContext context) {
    return GoogleMap(
      mapType: MapType.hybrid,
      initialCameraPosition: _kGooglePlex,
      onMapCreated: (GoogleMapController controller) {
        _controller.complete(controller);
      },
    );
  }
}

對於 web,它有點復雜,據我了解, google_maps_flutter_web似乎實際上不是一個可用版本(如果我錯了請糾正我)並且它實際上使用另一個 package 不是由 flutter 團隊google_maps 6.0.0開發的google_maps 6.0.0

google_maps_flutter_web的目標可能是擁有與google_maps_flutter ( google_maps_flutter_platform_interface ) 相同的 api 並無縫使用它,但我真的找不到如何使用它的示例......

我應該怎么go一下這個? 我對 google_maps_flutter_web 有什么誤解,它真的有效嗎? 或者我應該嘗試使用實際適用於google_maps的 google_maps 並僅根據kIsWeb切換小部件?

最終我找到了一個使用google_maps的解決方法,並將這個答案作為靈感:

  1. 抽象地圖控件
    import 'package:client_ojp4danube/map/map_widget_stub.dart'
        if (dart.library.html) 'package:client_ojp4danube/map/map_web_widget.dart'
        if (dart.library.io) 'package:client_ojp4danube/map/map_widget.dart';
    
    import 'package:flutter/material.dart';
    
    abstract class MapWidget extends StatefulWidget {
      factory MapWidget() => getMapWidget();
    }
  1. 使用 google_maps 的 WebMap 小部件:
    import 'dart:html';
    
    import 'package:client_ojp4danube/map/abstract_map_widget.dart';
    import 'package:flutter/cupertino.dart';
    import 'package:google_maps/google_maps.dart';
    import 'dart:ui' as ui;
    
    Widget getMap() {
      String htmlId = "7";
    
      // ignore: undefined_prefixed_name
      ui.platformViewRegistry.registerViewFactory(htmlId, (int viewId) {
        final myLatlng = new LatLng(30.2669444, -97.7427778);
    
        final mapOptions = new MapOptions()
          ..zoom = 8
          ..center = new LatLng(30.2669444, -97.7427778);
    
        final elem = DivElement()
          ..id = htmlId
          ..style.width = "100%"
          ..style.height = "100%"
          ..style.border = 'none';
    
        final map = GMap(elem, mapOptions);
    
        Marker(MarkerOptions()
          ..position = myLatlng
          ..map = map
          ..title = 'Hello World!');
    
        return elem;
      });
    
      return HtmlElementView(viewType: htmlId);
    }
    
    class WebMap extends StatefulWidget implements MapWidget {
      WebMap({Key? key}) : super(key: key);
    
      @override
      State<WebMap> createState() => WebMapState();
    }
    
    class WebMapState extends State<WebMap> {
      @override
      Widget build(BuildContext context) {
        return getMap();
      }
    }
    
    MapWidget getMapWidget() {
      print("Intra in get map web ");
      return WebMap();
    }
  1. 移動 Map 小部件
    import 'dart:async';
    
    import 'package:client_ojp4danube/map/abstract_map_widget.dart';
    import 'package:flutter/material.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    
    class MobileMap extends StatefulWidget implements MapWidget {
      MobileMap({Key? key}) : super(key: key);
    
      @override
      State<MobileMap> createState() => MobileMapState();
    }
    
    class MobileMapState extends State<MobileMap> {
      final Completer<GoogleMapController> _controller = Completer();
    
      static const CameraPosition _kGooglePlex = CameraPosition(
        target: LatLng(37.42796133580664, -122.085749655962),
        zoom: 14.4746,
      );
    
      @override
      Widget build(BuildContext context) {
        return GoogleMap(
          mapType: MapType.hybrid,
          initialCameraPosition: _kGooglePlex,
          onMapCreated: (GoogleMapController controller) {
            _controller.complete(controller);
          },
        );
      }
    }
    
    MapWidget getMapWidget() {
      return MobileMap();
    }
  1. getMapWidget - 存根
    import 'package:client_ojp4danube/map/abstract_map_widget.dart';
    
    // Created because importing dart.html on a mobile app breaks the build
    MapWidget getMapWidget() => throw UnsupportedError(
        'Cannot create a map without dart:html or google_maps_flutter');
  1. 實際使用將返回適合平台的小部件的抽象小部件
import 'package:client_ojp4danube/map/abstract_map_widget.dart';


class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(child: MapWidget()),
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

編輯:發布了一個新的官方插件: https://pub.dev/packages/google_maps_flutter_web 它已經可以與現有的 google_maps_flutter 插件一起使用,只需在 web/index.html 中添加您的 api 腳本。

正如用戶 exilonX 所建議的那樣,目前(22 年 4 月)在 Flutter web 和移動設備上使用 Google 地圖的方式是根據設備動態加載庫。 但是,他的回答缺少一些重要的細節。 我花了將近 1 小時才讓他的工作正常進行,因此我在這里分享一個更清晰、更有條理的解決方案,希望它能為您節省一些時間(由於編輯隊列很長,我無法編輯他的答案)。


文件夾結構:

\widget
   \map_widget.dart
   \web_map_widget.dart
   \mob_map_widget.dart
   \map_widget_stub.dart

地圖小部件:

在文件map_widget.dart ,您將擁有抽象的 MapWidget:

import 'package:flutter/material.dart';

import 'map_widget_stub.dart'
    if (dart.library.html) 'web_map_widget.dart'
    if (dart.library.io) 'mob_map_widget.dart';

abstract class MapWidget extends StatefulWidget {
  factory MapWidget() => getMapWidget();
}

注意:條件導入所需的唯一半列是在第二個 if 的末尾。


Web 地圖小部件:

此文件將包含 web 上顯示的 google map:

import 'dart:html';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:google_maps/google_maps.dart';

import 'map_widget.dart';

MapWidget getMapWidget() => WebMap();

class WebMap extends StatefulWidget implements MapWidget {
  WebMap({Key? key}) : super(key: key);

  @override
  State<WebMap> createState() => WebMapState();
}

class WebMapState extends State<WebMap> {
  @override
  Widget build(BuildContext context) {
    final String htmlId = "map";

    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(htmlId, (int viewId) {
      final mapOptions = MapOptions()
        ..zoom = 15.0
        ..center = LatLng(35.7560423, 139.7803552);

      final elem = DivElement()..id = htmlId;
      final map = GMap(elem, mapOptions);

      map.onCenterChanged.listen((event) {});
      map.onDragstart.listen((event) {});
      map.onDragend.listen((event) {});

      Marker(MarkerOptions()
        ..position = map.center
        ..map = map);

      return elem;
    });
    return HtmlElementView(viewType: htmlId);
  }
}

在這里您可以找到有關 web 實現的更多詳細信息。


移動地圖小部件:

此文件包含移動設備(android/ios)的實現:

import 'dart:async';

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

import 'map_widget.dart';

MapWidget getMapWidget() => MobileMap();

class MobileMap extends StatefulWidget implements MapWidget {
  MobileMap({Key? key}) : super(key: key);

  @override
  State<MobileMap> createState() => MobileMapState();
}

class MobileMapState extends State<MobileMap> {
  final Completer<GoogleMapController> _controller = Completer();

  static const CameraPosition _kFalentexHouse =
      CameraPosition(target: LatLng(44.497858579692135, 11.336362079086408));

  @override
  Widget build(BuildContext context) {
    return GoogleMap(
      mapType: MapType.hybrid,
      initialCameraPosition: _kFalentexHouse,
      onMapCreated: (GoogleMapController controller) {
        _controller.complete(controller);
      },
    );
  }
}

存根

最后,你需要一個存根:

import 'map_widget.dart';

//the error is shown in case of wrong version loaded on wrong platform
MapWidget getMapWidget() => throw UnsupportedError(
    'Cannot create a map without dart:html or google_maps_flutter');

用法

現在您可以將小部件 MapWidget 用作普通小部件:

Scaffold(
      body: Center(
        child: SizedBox(
          height: 300,
          width: 300,
          child: MapWidget(),
        ),
      ),
    );

注意:為了使 map 正常工作,您需要使用密鑰進行設置。 請參閱mobileweb的官方庫文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM