Andorid/Flutter的Dictionary也叫Map
使用Flutter版Google Maps 跟 location
(定位还有一套geolocator好像也很厉害, 不过两套都是Flutter Favorites)
要先去GCP生一把Google Maps API key
选择Maps SDK for iOS并启用
然後因为已经启用iOS了, 所以画面会变成这样
iOS Runner的AppDelegate
一样要import GoogleMaps
然後GMSServices.provideAPIKey
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("你钥匙掉了")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Android这边请
<manifest ...
<application ...
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR KEY HERE"/>
如果需要不同平台用不同的key
可以申请两只
然後点进去设定
如果切换帐号会看到这个报错
重新选取专案就好了
iOS:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
Android:
如果是Flutter1.12之前才需要特别处理,看这里
就是一个叫做GoogleMap的Widget
可以设定图层类型与起始点
根据Fullter惯例
一样是使用controller去控制widget
不过这边用了一个没见过的东西Completer
暂时没研究
Completer<GoogleMapController> _controller = Completer();
GoogleMap(
mapType: MapType.terrain,
initialCameraPosition: _kGooglePlex,
myLocationEnabled: _enableMyLocation,
myLocationButtonEnabled: true,
markers: Set<Marker>.of(_markerMap.values),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
)
可以看到在init里面有两个参数都是跟my location有关的
myLocationButtonEnabled就是右下角的定位按钮(预设为ture)
点了之後的逻辑套件已经处理好
iOS版的Google Maps应该没有这麽方便⚠️⚠️⚠️
myLocationEnabled就是在地图上要不要显示蓝点点(预设false)
若为true, 会要求权限
但是要求的时机也太丑了吧...就卡在这边
用了addPostFrameCallback
好啦是有好一点...
抱歉小弟学艺不精
暂时先用delayed
initState两秒後再要求(经实测XD, 1秒不要求, 3秒太久)
刚刚配对的controller就可以在这时使用
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kGooglePlex));
因为是要请圣兽守护在自身四方(这人写扣写到头壳坏掉)
所以要先取得目前位置
void _getCurrentLocation() async {
var location = new Location();
try {
_currentLocation = await location.getLocation();
print(_currentLocation);
} on Exception {
_currentLocation = null;
}
_addMarker(MarkerType.top);
_addMarker(MarkerType.bottom);
_addMarker(MarkerType.left);
_addMarker(MarkerType.right);
}
然後建立Marker, 加进GoogleMap的markers参数里
注意两点:
enum MarkerType {top, bottom, left, right}
Map<MarkerId, Marker> _markerMap = <MarkerId, Marker>{};
void _addMarker(MarkerType type) {
final MarkerId markerId = MarkerId("IDLF_$type");
final offset = 0.002;
LatLng latLng;
String snippet;
switch (type){
case MarkerType.top:
latLng = LatLng(_currentLocation.latitude + 0.001, _currentLocation.longitude);
snippet = "北~玄武";
break;
case MarkerType.bottom:
latLng = LatLng(_currentLocation.latitude - 0.003, _currentLocation.longitude);
snippet = "南~朱雀";
break;
case MarkerType.left:
latLng = LatLng(_currentLocation.latitude, _currentLocation.longitude - offset);
snippet = "左~青龙";
break;
case MarkerType.right:
latLng = LatLng(_currentLocation.latitude, _currentLocation.longitude + offset);
snippet = "右~白虎";
break;
}
final Marker marker = Marker(
markerId: markerId,
infoWindow: InfoWindow(title: "Hello~", snippet: snippet),
position: latLng,
);
if (!mounted) return;
setState(() {
_markerMap[markerId] = marker;
});
}
pub上面的范例就这样...有点崩溃
後来发现是在这边
然後套件里面也有@@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:icofont_flutter/icofont_flutter.dart';
import 'package:location/location.dart';
enum MarkerType {top, bottom, left, right}
class LessonPageMap extends StatefulWidget {
@override
_LessonPageMapState createState() => _LessonPageMapState();
}
class _LessonPageMapState extends State<LessonPageMap> {
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
Completer<GoogleMapController> _controller = Completer();
bool _enableMyLocation = false;
Map<MarkerId, Marker> _markerMap = <MarkerId, Marker>{};
LocationData _currentLocation;
void _getCurrentLocation() async {
var location = new Location();
try {
_currentLocation = await location.getLocation();
print(_currentLocation);
} on Exception {
_currentLocation = null;
}
_addMarker(MarkerType.top);
_addMarker(MarkerType.bottom);
_addMarker(MarkerType.left);
_addMarker(MarkerType.right);
}
void _addMarker(MarkerType type) {
final MarkerId markerId = MarkerId("IDLF_$type");
final offset = 0.002;
LatLng latLng;
String snippet;
switch (type){
case MarkerType.top:
latLng = LatLng(_currentLocation.latitude + 0.001, _currentLocation.longitude);
snippet = "北~玄武";
break;
case MarkerType.bottom:
latLng = LatLng(_currentLocation.latitude - 0.003, _currentLocation.longitude);
snippet = "南~朱雀";
break;
case MarkerType.left:
latLng = LatLng(_currentLocation.latitude, _currentLocation.longitude - offset);
snippet = "左~青龙";
break;
case MarkerType.right:
latLng = LatLng(_currentLocation.latitude, _currentLocation.longitude + offset);
snippet = "右~白虎";
break;
}
final Marker marker = Marker(
markerId: markerId,
infoWindow: InfoWindow(title: "Hello~", snippet: snippet),
position: latLng,
);
if (!mounted) return;
setState(() {
_markerMap[markerId] = marker;
});
}
@override
void initState() {
super.initState();
print("init");
print(DateTime.now());
Future.delayed(Duration(seconds: 2)).then((value) {
print("delayed");
print(DateTime.now());
setState(() {
_enableMyLocation = true;
_getCurrentLocation();
});
});
}
Future<void> _goToGoogle() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kGooglePlex));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Map")),
body: GoogleMap(
mapType: MapType.terrain,
initialCameraPosition: _kGooglePlex,
myLocationEnabled: _enableMyLocation,
myLocationButtonEnabled: true,
markers: Set<Marker>.of(_markerMap.values),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
floatingActionButton: FloatingActionButton(
child: Icon(IcoFontIcons.brandGoogle),
onPressed: _goToGoogle,
),
);
}
}
本集内容Android版请见:iOS Developer Learning Android. Lesson 22
下集预告:打包上架
//宣告全域变数 var v = 'global' let l = 'global' //建立fun...
我们今天先来介绍如何拿到资料,我们既然已经有看到了我们的个别聊天画面了,那当然我们需要有地方可以看...
新手在学写程序时一定常常看到物件、类别、介面、抽象、继承...奇怪的外星语,可能知道跟物件导向有关但...
感谢老天又让我有机会参加铁人赛,虽然今年一样面临了新的工作环境,但还是保有挑战与坚持的心态,BTW ...
在开发时,总缺少不了 bug 的存在, 那如何 debugger 就是所有开发者都很在意的问题了, ...