Skip to content

Commit 30bc3ea

Browse files
luisluis
authored andcommitted
feat: Taking Snapshots of the map
It is now possible to take snapshots of the displayed map. Fixes #25
1 parent 572d215 commit 30bc3ea

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

example/lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'package:apple_maps_flutter_example/place_circle.dart';
1616
import 'package:apple_maps_flutter_example/place_polygon.dart';
1717
import 'package:apple_maps_flutter_example/place_polyline.dart';
1818
import 'package:apple_maps_flutter_example/scrolling_map.dart';
19+
import 'package:apple_maps_flutter_example/snapshot.dart';
1920
import 'package:flutter/material.dart';
2021

2122
final List<ExamplePage> _allPages = <ExamplePage>[
@@ -32,6 +33,7 @@ final List<ExamplePage> _allPages = <ExamplePage>[
3233
PlaceCirclePage(),
3334
ScrollingMapPage(),
3435
MapUpdatePage(),
36+
SnapshotPage(),
3537
];
3638

3739
class MapsDemo extends StatelessWidget {

example/lib/snapshot.dart

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// ignore_for_file: public_member_api_docs
6+
7+
import 'dart:typed_data';
8+
9+
import 'package:apple_maps_flutter_example/page.dart';
10+
import 'package:flutter/material.dart';
11+
import 'package:apple_maps_flutter/apple_maps_flutter.dart';
12+
13+
const CameraPosition _kInitialPosition =
14+
CameraPosition(target: LatLng(-33.852, 151.211), zoom: 11.0);
15+
16+
class SnapshotPage extends ExamplePage {
17+
SnapshotPage()
18+
: super(const Icon(Icons.camera_alt), 'Take a snapshot of the map');
19+
20+
@override
21+
Widget build(BuildContext context) {
22+
return _SnapshotBody();
23+
}
24+
}
25+
26+
class _SnapshotBody extends StatefulWidget {
27+
@override
28+
_SnapshotBodyState createState() => _SnapshotBodyState();
29+
}
30+
31+
class _SnapshotBodyState extends State<_SnapshotBody> {
32+
AppleMapController? _mapController;
33+
Uint8List? _imageBytes;
34+
35+
@override
36+
Widget build(BuildContext context) {
37+
return Padding(
38+
padding: const EdgeInsets.all(16),
39+
child: Column(
40+
crossAxisAlignment: CrossAxisAlignment.stretch,
41+
children: [
42+
SizedBox(
43+
height: 180,
44+
child: AppleMap(
45+
onMapCreated: onMapCreated,
46+
initialCameraPosition: _kInitialPosition,
47+
),
48+
),
49+
TextButton(
50+
child: Text('Take a snapshot'),
51+
onPressed: () async {
52+
final imageBytes = await _mapController?.takeSnapshot();
53+
setState(() {
54+
_imageBytes = imageBytes;
55+
});
56+
},
57+
),
58+
Container(
59+
decoration: BoxDecoration(color: Colors.blueGrey[50]),
60+
height: 180,
61+
child: _imageBytes != null ? Image.memory(_imageBytes!) : null,
62+
),
63+
],
64+
),
65+
);
66+
}
67+
68+
void onMapCreated(AppleMapController controller) {
69+
_mapController = controller;
70+
}
71+
}

ios/Classes/MapView/AppleMapController.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class AppleMapController: NSObject, FlutterPlatformView {
1616
var options: [String: Any]
1717
var onCalloutTapGestureRecognizer: UITapGestureRecognizer?
1818
var currentlySelectedAnnotation: String?
19+
var snapShotOptions: MKMapSnapshotter.Options = MKMapSnapshotter.Options()
20+
var snapShot: MKMapSnapshotter?
1921

2022
let availableCaps: Dictionary<String, CGLineCap> = [
2123
"buttCap": CGLineCap.butt,
@@ -78,7 +80,7 @@ public class AppleMapController: NSObject, FlutterPlatformView {
7880
}
7981

8082
private func setMethodCallHandlers() {
81-
channel.setMethodCallHandler({ [unowned self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
83+
channel.setMethodCallHandler({ [unowned self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
8284
if let args :Dictionary<String, Any> = call.arguments as? Dictionary<String,Any> {
8385
switch(call.method) {
8486
case "annotations#update":
@@ -151,6 +153,10 @@ public class AppleMapController: NSObject, FlutterPlatformView {
151153
case "map#isMyLocationButtonEnabled":
152154
result(self.mapView.isMyLocationButtonShowing ?? false)
153155
break
156+
case "map#takeSnapshot":
157+
self.takeSnapshot(onCompletion: { (snapshot: FlutterStandardTypedData?, error: Error?) -> Void in
158+
result(snapshot ?? error)
159+
})
154160
case "map#getMinMaxZoomLevels":
155161
result([self.mapView.minZoomLevel, self.mapView.maxZoomLevel])
156162
break
@@ -341,3 +347,25 @@ extension AppleMapController: MKMapViewDelegate {
341347
return MKOverlayRenderer()
342348
}
343349
}
350+
351+
extension AppleMapController {
352+
private func takeSnapshot(onCompletion: @escaping (FlutterStandardTypedData?, Error?) -> Void) {
353+
// MKMapSnapShotOptions setting.
354+
snapShotOptions.region = self.mapView.region
355+
snapShotOptions.size = self.mapView.frame.size
356+
snapShotOptions.scale = UIScreen.main.scale
357+
358+
// Set MKMapSnapShotOptions to MKMapSnapShotter.
359+
snapShot = MKMapSnapshotter(options: snapShotOptions)
360+
361+
snapShot?.cancel()
362+
363+
snapShot?.start(completionHandler: {(snapshot: MKMapSnapshotter.Snapshot?, error: Error?) -> Void in
364+
if let imageData = snapshot?.image.pngData() {
365+
onCompletion(FlutterStandardTypedData.init(bytes: imageData), nil)
366+
} else {
367+
onCompletion(nil, error)
368+
}
369+
})
370+
}
371+
}

lib/src/controller.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,9 @@ class AppleMapController {
233233
final doubles = List<double>.from(point?['point']);
234234
return Offset(doubles.first, doubles.last);
235235
}
236+
237+
/// Returns the image bytes of the map
238+
Future<Uint8List?> takeSnapshot() {
239+
return channel.invokeMethod<Uint8List>('map#takeSnapshot');
240+
}
236241
}

0 commit comments

Comments
 (0)