Skip to content

Commit

Permalink
feat: Taking Snapshots of the map
Browse files Browse the repository at this point in the history
It is now possible to take snapshots of the displayed map.

Fixes #25
  • Loading branch information
luis authored and luis committed Jul 1, 2021
1 parent 572d215 commit 30bc3ea
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 1 deletion.
2 changes: 2 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:apple_maps_flutter_example/place_circle.dart';
import 'package:apple_maps_flutter_example/place_polygon.dart';
import 'package:apple_maps_flutter_example/place_polyline.dart';
import 'package:apple_maps_flutter_example/scrolling_map.dart';
import 'package:apple_maps_flutter_example/snapshot.dart';
import 'package:flutter/material.dart';

final List<ExamplePage> _allPages = <ExamplePage>[
Expand All @@ -32,6 +33,7 @@ final List<ExamplePage> _allPages = <ExamplePage>[
PlaceCirclePage(),
ScrollingMapPage(),
MapUpdatePage(),
SnapshotPage(),
];

class MapsDemo extends StatelessWidget {
Expand Down
71 changes: 71 additions & 0 deletions example/lib/snapshot.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

import 'dart:typed_data';

import 'package:apple_maps_flutter_example/page.dart';
import 'package:flutter/material.dart';
import 'package:apple_maps_flutter/apple_maps_flutter.dart';

const CameraPosition _kInitialPosition =
CameraPosition(target: LatLng(-33.852, 151.211), zoom: 11.0);

class SnapshotPage extends ExamplePage {
SnapshotPage()
: super(const Icon(Icons.camera_alt), 'Take a snapshot of the map');

@override
Widget build(BuildContext context) {
return _SnapshotBody();
}
}

class _SnapshotBody extends StatefulWidget {
@override
_SnapshotBodyState createState() => _SnapshotBodyState();
}

class _SnapshotBodyState extends State<_SnapshotBody> {
AppleMapController? _mapController;
Uint8List? _imageBytes;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: 180,
child: AppleMap(
onMapCreated: onMapCreated,
initialCameraPosition: _kInitialPosition,
),
),
TextButton(
child: Text('Take a snapshot'),
onPressed: () async {
final imageBytes = await _mapController?.takeSnapshot();
setState(() {
_imageBytes = imageBytes;
});
},
),
Container(
decoration: BoxDecoration(color: Colors.blueGrey[50]),
height: 180,
child: _imageBytes != null ? Image.memory(_imageBytes!) : null,
),
],
),
);
}

void onMapCreated(AppleMapController controller) {
_mapController = controller;
}
}
30 changes: 29 additions & 1 deletion ios/Classes/MapView/AppleMapController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class AppleMapController: NSObject, FlutterPlatformView {
var options: [String: Any]
var onCalloutTapGestureRecognizer: UITapGestureRecognizer?
var currentlySelectedAnnotation: String?
var snapShotOptions: MKMapSnapshotter.Options = MKMapSnapshotter.Options()
var snapShot: MKMapSnapshotter?

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

private func setMethodCallHandlers() {
channel.setMethodCallHandler({ [unowned self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
channel.setMethodCallHandler({ [unowned self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if let args :Dictionary<String, Any> = call.arguments as? Dictionary<String,Any> {
switch(call.method) {
case "annotations#update":
Expand Down Expand Up @@ -151,6 +153,10 @@ public class AppleMapController: NSObject, FlutterPlatformView {
case "map#isMyLocationButtonEnabled":
result(self.mapView.isMyLocationButtonShowing ?? false)
break
case "map#takeSnapshot":
self.takeSnapshot(onCompletion: { (snapshot: FlutterStandardTypedData?, error: Error?) -> Void in
result(snapshot ?? error)
})
case "map#getMinMaxZoomLevels":
result([self.mapView.minZoomLevel, self.mapView.maxZoomLevel])
break
Expand Down Expand Up @@ -341,3 +347,25 @@ extension AppleMapController: MKMapViewDelegate {
return MKOverlayRenderer()
}
}

extension AppleMapController {
private func takeSnapshot(onCompletion: @escaping (FlutterStandardTypedData?, Error?) -> Void) {
// MKMapSnapShotOptions setting.
snapShotOptions.region = self.mapView.region
snapShotOptions.size = self.mapView.frame.size
snapShotOptions.scale = UIScreen.main.scale

// Set MKMapSnapShotOptions to MKMapSnapShotter.
snapShot = MKMapSnapshotter(options: snapShotOptions)

snapShot?.cancel()

snapShot?.start(completionHandler: {(snapshot: MKMapSnapshotter.Snapshot?, error: Error?) -> Void in
if let imageData = snapshot?.image.pngData() {
onCompletion(FlutterStandardTypedData.init(bytes: imageData), nil)
} else {
onCompletion(nil, error)
}
})
}
}
5 changes: 5 additions & 0 deletions lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,9 @@ class AppleMapController {
final doubles = List<double>.from(point?['point']);
return Offset(doubles.first, doubles.last);
}

/// Returns the image bytes of the map
Future<Uint8List?> takeSnapshot() {
return channel.invokeMethod<Uint8List>('map#takeSnapshot');
}
}

0 comments on commit 30bc3ea

Please sign in to comment.