在手机和网络上使用 Google flutter 地图
Using Google Maps in flutter for both mobile and web
我正在开发一个 flutter 应用程序,它应该具有适用于网络和移动设备的通用代码库。
我的应用程序将有一个 google 地图,据我所知,没有一个包可以满足所有平台。
google_maps_flutter - seems to work only for mobile (IOS / Android)
google_maps_flutter_web - seems to work only for web
所以很可能我必须创建两个单独的 MapWidgets,一个用于网络,一个用于移动设备,使用这些单独的包。
移动设备:
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);
},
);
}
}
对于网络,它有点复杂,据我所知,google_maps_flutter_web
似乎不是一个可用的版本,(如果我错了请纠正我)它实际上使用了另一个不是由 flutter 团队开发的包 google_maps 6.0.0
.
google_maps_flutter_web
的objective大概是和google_maps_flutter
(google_maps_flutter_platform_interface
)一样的api,无缝使用,但是我做不到'真的找不到如何使用它的示例...
我该怎么办?我误认为 google_maps_flutter_web 的任何更改实际上有效吗?或者我应该尝试使用实际上适用于网络的 google_maps
并根据 kIsWeb
?
切换小部件
最终我找到了一个使用 google_maps
和 作为灵感的解决方法:
- 抽象地图小部件
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();
}
- 使用 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();
}
- 移动地图小部件
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();
}
- 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');
- 实际使用抽象小部件将return适合平台的小部件
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 插件一起使用,只需将您的 api 脚本添加到 web/index.html .
正如用户 exilonX 所建议的,当前(22 年 4 月)在 Flutter 网络和移动设备上使用 Google 地图的方式是根据设备动态加载库。但是,他的回答缺少一些重要的细节。我花了将近 1 小时才让他的工作正常进行,因此我在这里分享一个更清晰、更有条理的解决方案,希望它能为您节省一些时间(由于编辑队列很长,我无法编辑他的答案)。
文件夹结构:
\widget
\map_widget.dart
\web_map_widget.dart
\mob_map_widget.dart
\map_widget_stub.dart
MapWidget:
在文件 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 MapWidget:
此文件将包含网络上显示的 google 地图:
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);
}
}
Here 您可以找到有关网络实施的更多详细信息。
移动地图小部件:
此文件包含移动设备 (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(),
),
),
);
的官方库文档
我正在开发一个 flutter 应用程序,它应该具有适用于网络和移动设备的通用代码库。
我的应用程序将有一个 google 地图,据我所知,没有一个包可以满足所有平台。
google_maps_flutter - seems to work only for mobile (IOS / Android)
google_maps_flutter_web - seems to work only for web
所以很可能我必须创建两个单独的 MapWidgets,一个用于网络,一个用于移动设备,使用这些单独的包。
移动设备:
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);
},
);
}
}
对于网络,它有点复杂,据我所知,google_maps_flutter_web
似乎不是一个可用的版本,(如果我错了请纠正我)它实际上使用了另一个不是由 flutter 团队开发的包 google_maps 6.0.0
.
google_maps_flutter_web
的objective大概是和google_maps_flutter
(google_maps_flutter_platform_interface
)一样的api,无缝使用,但是我做不到'真的找不到如何使用它的示例...
我该怎么办?我误认为 google_maps_flutter_web 的任何更改实际上有效吗?或者我应该尝试使用实际上适用于网络的 google_maps
并根据 kIsWeb
?
最终我找到了一个使用 google_maps
和
- 抽象地图小部件
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();
}
- 使用 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();
}
- 移动地图小部件
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();
}
- 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');
- 实际使用抽象小部件将return适合平台的小部件
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 插件一起使用,只需将您的 api 脚本添加到 web/index.html .
正如用户 exilonX 所建议的,当前(22 年 4 月)在 Flutter 网络和移动设备上使用 Google 地图的方式是根据设备动态加载库。但是,他的回答缺少一些重要的细节。我花了将近 1 小时才让他的工作正常进行,因此我在这里分享一个更清晰、更有条理的解决方案,希望它能为您节省一些时间(由于编辑队列很长,我无法编辑他的答案)。
文件夹结构:
\widget
\map_widget.dart
\web_map_widget.dart
\mob_map_widget.dart
\map_widget_stub.dart
MapWidget:
在文件 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 MapWidget:
此文件将包含网络上显示的 google 地图:
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);
}
}
Here 您可以找到有关网络实施的更多详细信息。
移动地图小部件:
此文件包含移动设备 (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(),
),
),
);
的官方库文档