Accueil
Explorer
Soumettre la recherche
Mettre en ligne
S’identifier
S’inscrire
Publicité
Check these out next
Implementing WebAuthn & FAPI supports on Keycloak
Yuichi Nakamura
今更聞けない電子認証入門 - OAuth 2.0/OIDCからFIDOまで -
Naoto Miyachi
Ambiente de CI/CD com Google Cloud
Alvaro Viebrantz
PDSを実現するにあたっての技術動向の紹介 (OAuth, OpenID Connect, UMAなど)
Tatsuo Kudo
Introduction and Deep Dive Into Containerd
Kohei Tokunaga
Terraform GitOps on Codefresh
Codefresh
AWS Code Services
Amazon Web Services
Spring Native and Spring AOT
VMware Tanzu
1
sur
31
Top clipped slide
怎樣在 Flutter app 中使用 Google Maps
9 Feb 2023
•
0 j'aime
0 j'aime
×
Soyez le premier à aimer ceci
afficher plus
•
156 vues
vues
×
Nombre de vues
0
Sur Slideshare
0
À partir des intégrations
0
Nombre d'intégrations
0
Télécharger maintenant
Télécharger pour lire hors ligne
Signaler
Technologie
放置地圖 Widget 新增 Marker 新增 Polyline 計算 zoom level 顯示 information window 移動地圖、設定樣式 其他…
Weizhong Yang
Suivre
Software engineer à KKBOX
Publicité
Publicité
Publicité
Recommandé
給 iOS 工程師的 Flutter 開發
Weizhong Yang
7.8K vues
•
50 diapositives
導入 Flutter 前你應該知道的事
Weizhong Yang
6K vues
•
43 diapositives
Flutter 踩雷心得
Weizhong Yang
5.9K vues
•
41 diapositives
DevDay: A Tale of Corda Slack Adventures, R3
R3
618 vues
•
74 diapositives
The Image that called me - Active Content Injection with SVG Files
Mario Heiderich
10K vues
•
29 diapositives
Flutter
Dave Chao
292 vues
•
51 diapositives
Contenu connexe
Présentations pour vous
(20)
Implementing WebAuthn & FAPI supports on Keycloak
Yuichi Nakamura
•
2.9K vues
今更聞けない電子認証入門 - OAuth 2.0/OIDCからFIDOまで -
Naoto Miyachi
•
1.6K vues
Ambiente de CI/CD com Google Cloud
Alvaro Viebrantz
•
488 vues
PDSを実現するにあたっての技術動向の紹介 (OAuth, OpenID Connect, UMAなど)
Tatsuo Kudo
•
7.3K vues
Introduction and Deep Dive Into Containerd
Kohei Tokunaga
•
357 vues
Terraform GitOps on Codefresh
Codefresh
•
2.4K vues
AWS Code Services
Amazon Web Services
•
4.1K vues
Spring Native and Spring AOT
VMware Tanzu
•
1.5K vues
Hacking Adobe Experience Manager sites
Mikhail Egorov
•
12.8K vues
Locking the Throneroom 2.0
Mario Heiderich
•
6.4K vues
FIDO Authentication: Unphishable MFA for All
FIDO Alliance
•
470 vues
Introduction to helm
Jeeva Chelladhurai
•
3.3K vues
Real-time Web Application with Socket.IO, Node.js, and Redis
York Tsai
•
33.4K vues
Node js overview
Eyal Vardi
•
1.5K vues
Enabling Compliance with GDPR on AWS
Amazon Web Services
•
1.9K vues
Creating Apps with .NET MAUI
Brandon Minnick, MBA
•
837 vues
REST API Pentester's perspective
SecuRing
•
4.7K vues
Macros no asterisk
Vicente Nobre
•
3.3K vues
Wireguard VPN
All Things Open
•
621 vues
U2F/FIDO2 implementation of YubiKey
Haniyama Wataru
•
1.8K vues
Similaire à 怎樣在 Flutter app 中使用 Google Maps
(20)
再接再勵學 Swift 程式設計
政斌 楊
•
601 vues
I os 07
信嘉 陳
•
673 vues
2016輕鬆開發自有網路地圖工作坊 進階班 0701
family
•
835 vues
Google map api接口整理
lileinba
•
988 vues
Responsive Web UI Design
jay li
•
4.4K vues
Html5移动web应用开发(PhoneGap)
amd6400
•
588 vues
Html5移动web应用开发(PhoneGap)
amd6400
•
1K vues
Study mapapi v0.1
Paul Yang
•
365 vues
I os 02
信嘉 陳
•
458 vues
AngularJS training in Luster
Jason Chung
•
13.9K vues
Android 智慧型手機程式設計
Kyle Lin
•
865 vues
Behind Tetris5
Junwen Sun
•
859 vues
Anroid development part.1
RANK LIU
•
1K vues
行動商務實務 - PhoneGap Advance
My own sweet home!
•
557 vues
I os 01
信嘉 陳
•
520 vues
Introduction to corona sdk
馬 萬圳
•
144.5K vues
HTML5移动WEB应用程序开发(PhoneGap)
amd6400
•
679 vues
HTML5移动应用开发分享会(PhoneGap)
amd6400
•
749 vues
2021laravelconftwslides12
LiviaLiaoFontech
•
101 vues
I os 16
信嘉 陳
•
710 vues
Publicité
Plus de Weizhong Yang
(20)
Flutter BLE
Weizhong Yang
•
151 vues
關於延長役期這件事情
Weizhong Yang
•
862 vues
Dart null safety
Weizhong Yang
•
703 vues
Github Actions
Weizhong Yang
•
945 vues
iPlayground: CarPlay and MFI Hearing Aids
Weizhong Yang
•
924 vues
CocoaPods private repo
Weizhong Yang
•
1.6K vues
那些年被蘋果 Ban 掉的 API
Weizhong Yang
•
3.2K vues
給 iOS 工程師的 Vue.js 開發
Weizhong Yang
•
10.3K vues
苦集滅道:透過開發客製 Sketch Plug-in 改善產品設計流程
Weizhong Yang
•
3.3K vues
使用 switch/case 重構程式碼
Weizhong Yang
•
8.5K vues
怎樣寫出比較沒有問題的 Code
Weizhong Yang
•
13.3K vues
貪食蛇
Weizhong Yang
•
5.4K vues
Aspect Oriented Programming
Weizhong Yang
•
2.6K vues
Mac OS X 與 iOS 的 Audio API
Weizhong Yang
•
2.9K vues
Html 5 native drag
Weizhong Yang
•
971 vues
Retina mac
Weizhong Yang
•
1.1K vues
Python 的文件系統
Weizhong Yang
•
789 vues
Input Method Kit
Weizhong Yang
•
3.3K vues
Refactoring
Weizhong Yang
•
816 vues
Core animation
Weizhong Yang
•
1.8K vues
Dernier
(20)
thothmind
MarlowChen
•
5 vues
Kevin Lognone Agenda at the European Innovation Week 2023 歐盟創新週
Kevin Lognoné
•
2 vues
①【加州大学圣地亚哥分校毕业证文凭学位证书|工艺完美复刻】
34asdcx
•
3 vues
☀️《佩斯毕业证仿真》
jjkjkijk
•
3 vues
☀️【百年理工学院毕业证成绩单留学生首选】
15sad
•
2 vues
☀️【伦敦国王学院毕业证成绩单留学生首选】
25mjhd12
•
2 vues
☀️【路易斯维尔大学毕业证成绩单留学生首选】
2125nuh
•
2 vues
国外学历【萨塞克斯大学研究生文凭毕业证留学生首选】
1w53dacxz
•
2 vues
☀️【巴斯大学毕业证成绩单留学生首选】
25mjhd12
•
2 vues
①【温哥华岛大学毕业证文凭学位证书|工艺完美复刻】
love445ds
•
2 vues
☀️【爱丁堡龙比亚大学毕业证成绩单留学生首选】
15sad
•
2 vues
留信网认证可查【路易斯安那理工大学文凭证书毕业证购买】
1lkjhg
•
2 vues
☀️【基尔大学毕业证成绩单留学生首选】
25mjhd12
•
2 vues
☀️【杜塞尔多夫大学毕业证成绩单留学生首选】
bjd42as
•
2 vues
留信网认证可查【中央昆士兰大学文凭证书毕业证购买】
khh123kj
•
4 vues
Configuration of Meter_Data_Management_Systems.pdf
Bhekumuzi Xaba
•
3 vues
《索尔福德大学毕业证|学位证书校内仿真版本》
w124dsa
•
2 vues
①【凤凰城大学毕业证文凭学位证书|工艺完美复刻】
0987hgh789
•
5 vues
☀️【北卡罗来纳大学格林波若分校毕业证成绩单留学生首选】
25mjhd12
•
2 vues
留信网认证可查【加州州立大学圣贝纳迪诺分校文凭证书毕业证购买】
32lkhng
•
2 vues
Publicité
怎樣在 Flutter app 中使用 Google Maps
怎樣在 Flutter App
中整合 Google Maps Weizhong Yang a.k.a zonble zonble@gmail.com
關於我 Weizhong Yang a.k.a
zonble • 最近⼗年都在做 App 開發 • Flutter GDE (2019-) • Developer Manager at Cerence Inc (2020-) • iOS Developer Lead at KKBOX (2011-2020) • 今年做的事:講了⼀場 Flutter Desktop plugin 開發,下半年常跑⾦⾨,開始重 寫⼆⼗年前的《防區狀況三⽣效》的新章… • Twitter @zonble
還記得我去年的題⽬? 總之,今年我們把去年題⽬裡頭的那個 App 商品化了
Cerence Link
這個 App 有哪些功能? •
顯示 ODB 傳來的讀數(速度、溫度等) • 在地圖上顯示⽬前⾞⼦與⼿機的位置 • 顯示 Journey(每次⾞⼦上⽕/熄⽕之間的駕駛紀錄) • 路徑規劃: • 怎樣⾛到我的⾞⼦? • 怎樣去加油站/維修站/⾃訂地點? • Geo Fence 規劃(在某個區域開⾞時發出警告) • Curfew 規劃(在某個時間開⾞發出警告) • 各種警告—急彎、急停、撞擊、進⼊ Geo Fence
這個 App ⼤量需要顯示地圖
Agenda • 放置地圖 Widget •
新增 Marker • 新增 Polyline • 計算 zoom level • 顯示 information window • 移動地圖、設定樣式 • 其他…
會⽤到哪些 package? • google_maps_ fl utter:
The o ffi cial package • custom_info_window: Show custom window in the map • google_place: Google Place API • google_maps_utils: 地圖相關計算功能 • fl utter_polyline_points: encode/decode Google polyline string
基本導⼊ • 更新 pubspec.yaml •
加⼊ google_maps_ fl utter • fl utter pub get • 需要⼀些平台權限,例如使⽤ GPS 等,需要在 iOS 的 Info Plist 以及 Android 的 Manifest 裡頭加上對應設定 • Android 上需要安裝 Google Maps App
基本⽤法 GoogleMap( minMaxZoomPreference: MinMaxZoomPreference(0, 16), initialCameraPosition:
LatLng(…..), mapType: MapType.normal, mapToolbarEnabled: false, zoomControlsEnabled: false, rotateGesturesEnabled: false, scrollGesturesEnabled: false, zoomGesturesEnabled: false, myLocationButtonEnabled: false, )
Platform View • Google
Maps Widget 是⼀個 Platform View • 將 Native View 包進 Flutter 中 • 現在我們也可以在 Platform View 上重疊任意的 Flutter Widget
加上 Marker fi nal startPoint
= await BitmapDescriptor.fromAssetImage( ImageCon fi guration(size: Size(100, 100)), ‘asset/image.png’); var markers = []; fi nal startPoint = Marker( markerId: MarkerId('pin-start'), icon: _startPoint, anchor: O ff set(0.5, 0.5), position: LatLng(….)), zIndex: 10, ); markers.add(startPoint); GoogleMap(markers:markers); Image 的載⼊可以使⽤ Future Builder 需要注意載⼊的解析度(@2x、@3x)
放置 SVG Marker import
'dart:ui' as ui; import ‘package: fl utter_svg/ fl utter_svg.dart'; static Future<BitmapDescriptor?> bitmapDescriptorFromSvgAsset( BuildContext context, String assetName, Size size) async { // Read SVG fi le as String String svgString = await DefaultAssetBundle.of(context).loadString(assetNa me); // Create DrawableRoot from SVG String DrawableRoot svgDrawableRoot = await svg.fromSvgString(svgString, 'a'); // toPicture() and toImage() don't seem to be pixel ratio aware, so we calculate the actual sizes here MediaQueryData queryData = MediaQuery.of(context); double devicePixelRatio = queryData.devicePixelRatio; double width = size.width * devicePixelRatio; // where 32 is your SVG's original width double height = size.height * devicePixelRatio; // same thing // Convert to ui.Picture ui.Picture picture = svgDrawableRoot.toPicture(size: Size(width, height)); ui.Image image = await picture.toImage(width.toInt(), height.toInt()); ByteData? bytes = await image.toByteData(format: ui.ImageByteFormat.png); fi nal bu ff er = bytes?.bu ff er; if (bu ff er != null) { return BitmapDescriptor.fromBytes(bu ff er.asUint8List()); } return null; }
加上 Polyline fi nal points
= <LatLng>[……]; var lines = <Polyline>{}; fi nal line = Polyline( polylineId: PolylineId('planning_route'), color: planningRouteColor, width: 6, points: points, ); lines.add(line); GoogleMap(polylines: polylines);
根據 route 計算
zoom level num latRad(lat) { var sin = math.sin(lat * math.pi / 180); var radX2 = math.log((1 + sin) / (1 - sin)) / 2; return math.max(math.min(radX2, math.pi), -math.pi) / 2; } num zoom(mapPx, worldPx, fraction) { if (fraction == 0) { return 21; } fi nal left = math.log(mapPx / worldPx / fraction); fi nal result = (left. fl oor() / math.ln2); return result; } List<num> _getRegion(num screenWidth, num screenHeight) { num zoomMax = 16.0; num? minLong = ….; num? maxLong = ….; num? minLat = ….; num? maxLat = ….; fi nal latFraction = (latRad(maxLat) - latRad(minLat)) / math.pi; fi nal lngDi ff = maxLong - minLong; fi nal lngFraction = ((lngDi ff < 0) ? (lngDi ff + 360) : lngDi ff ) / 360; num latZoom = zoom(screenHeight, 256, latFraction); num lngZoom = zoom(screenWidth, 256, lngFraction); fi nal zoomLevel = math.min(math.min(latZoom, lngZoom) * 0.99, zoomMax); fi nal centerLat = (maxLat + minLat) / 2; fi nal centerLong = (maxLong + minLong) / 2; return [centerLat, centerLong, zoomLevel]; }
Custom Info Window custom_info_window https://pub.dev/packages/custom_info_window
Custom Info Window Stack( children:
[ PreloadMapWrapper( child: GoogleMap( onCameraMove: (position) { _customInfoWindowController.onCameraMove?.call(); }, onMapCreated: (GoogleMapController controller) { _customInfoWindowController.googleMapController = controller; _mapController = controller; }, ), ), CustomInfoWindow( controller: _customInfoWindowController, width: 274, height: 189, o ff set: 30, ), ], ); var _customInfoWindowController = CustomInfoWindowController(); _customInfoWindowController.addInfoWindow?.call(window, LatLng(…)); _customInfoWindowController.hideInfoWindow?.call();
Circle fi nal pin =
Circle( circleId: CircleId('circle'), radius: radius.toDouble(), fi llColor: …., strokeColor: …., center: location, ); fi nal circles = <Circle>{}; circles.add(pin); GoogleMap( circles: circles )
如何更新地圖內容 • 可以透過 setState()
更新包含 GoogleMap Widget 的 Widget • 如果使⽤ Bloc,可以將 GoogleMap Widget 放在 BlocBuilder 中 • 以上⽅式可以修改有哪些 Marker、Polyline 與 Circle,不會改變地圖的 zoom level 與中央位置
移動地圖 Future<void> goTo(num latitude,
num longitude) async { fi nal position = CameraPosition( target: LatLng(latitude.toDouble(), longitude.toDouble()), zoom: zoomLevel, ); _mapController?.animateCamera(CameraUpdate.newCameraPosition(position)); } GoogleMapController? _mapController GoogleMap( onMapCreated: (GoogleMapController controller) { _mapController = controller; }, ),
進階設置 • liteModeEnabled:⽤在完全靜態的地圖上 • indoorViewEnabled:顯示室內導航 •
tra ffi cEnabled:顯示交通狀況 • buildingsEnabled:顯示建築物模型
設定地圖樣式 • GoogleMap Widget
本身 沒有 light/dark mode • ⽽是設置整個 Map 樣式 的 JSON • https:// console.cloud.google.co m/projectselector2/ google/maps-apis/studio/ styles?pli=1
設定地圖樣式 rootBundle.loadString('assets/map_style.txt').then((string) { _mapStyle =
string; }); GoogleMap( onMapCreated: (GoogleMapController controller) { mapController = controller; mapController.setMapStyle(_mapStyle); } ); 這個 Future 也可以考慮放在 FutureBuilder 裡頭
疑難雜症 • Android 上,如果
App 放在背景再回到前景,之後 GoogleMap Widget 可 能畫⾯花掉,或是有奇怪的狀況 • 可以⽤ WidgetsBindingObserver 偵測回到前景重繪 (didChangeAppLifecycleState) • 重新 Build GoogleMap Widget 也不⾒得會重繪 • 但是呼叫 setMapStyle ⼀定可以重繪
地點搜尋
地點搜尋 fi nal _googlePlace =
GooglePlace(kGooglePlacesApikey); Future<TextSearchResponse?> _callGooglePlaceAPI(String keyword, { required double lat, required double lng }) async { return await _googlePlace.search.getTextSearch(keyword, location: Location(lat: lat, lng: lng), ); }
路徑規劃
路徑規劃 PolylineResult result =
await PolylinePoints().getRouteBetweenCoordinates( kGoogleDirectionsApiKey, PointLatLng(lat1, lng1), PointLatLng(lat2, lng2), travelMode: TravelMode.driving, ); import 'package: fl utter_polyline_points/ fl utter_polyline_points.dart';
路徑偏移(Route deviation) • 判斷⽬前的
GPS 位置是否偏移規劃的路徑 • 可以使⽤ google_map_polyutil • 呼叫 PolyUtils.isLocationOnEdgeTolerance,判斷座標是否在路徑上 • 還有其他⼯具
Recap • 放置地圖 Widget •
新增 Marker • 新增 Polyline • 計算 zoom level • 顯示 information window • 移動地圖、設定樣式 • 其他…
That’s all 謝謝⼤家
Publicité