Instantánea de MKMapView en iOS7
mapkit mkmapsnapshotter (3)
Para iOS 10 y superior puede usar la clase UIGraphicsImageRenderer
para representar cualquier vista a la imagen (en caso de que no quiera usar MKMapSnapshotter
, ya que estoy usando MapBox
).
let render = UIGraphicsImageRenderer(size: self.mapView.bounds.size)
let image = render.image { ctx in
self.mapView.drawHierarchy(in: self.mapView.bounds, afterScreenUpdates: true)
}
Resultado :
Estoy intentando crear una instantánea de una aplicación MKMapView en iOS7 de la misma manera que se recomienda en todas partes para versiones anteriores de iOS:
- (UIImage*) renderMapViewToImage
{
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, NO, 0.0);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Sin embargo, la imagen devuelta es un rectángulo negro con un punto azul de ubicación actual en la parte superior. He intentado usar diferentes subcapas de mapView también, pero el resultado es siempre el mismo.
¿Alguien sabe cómo tomar instantáneas MKMapView en iOS7?
Puede usar MKMapSnapshotter
y capturar la image
del MKMapSnapshot
resultante. Vea la discusión del video de la sesión de la WWDC 2013, Poniendo el kit de mapas en perspectiva .
Por ejemplo:
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.region = self.mapView.region;
options.scale = [UIScreen mainScreen].scale;
options.size = self.mapView.frame.size;
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
UIImage *image = snapshot.image;
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:[self snapshotFilename] atomically:YES];
}];
Habiendo dicho eso, la solución renderInContext
todavía funciona para mí. Hay notas sobre solo hacer eso en la cola principal en iOS7, pero todavía parece funcionar. Pero MKMapSnapshotter
parece ser la solución más adecuada para iOS7.
Si desea incluir algunas anotaciones en la instantánea, debe dibujarlas manualmente (!). Esto se discute con cierto detalle al final del video de Putting Map Kit in Perspective . Debo decir que esta es una de las implementaciones menos elegantes que he visto recomendar a Apple. De todos modos, en iOS, podría verse como:
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.region = self.mapView.region;
options.scale = [UIScreen mainScreen].scale;
options.size = self.mapView.frame.size;
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
// get the image associated with the snapshot
UIImage *image = snapshot.image;
// Get the size of the final image
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
// Get a standard annotation view pin. Clearly, Apple assumes that we''ll only want to draw standard annotation pins!
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
UIImage *pinImage = pin.image;
// ok, let''s start to create our final image
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
// first, draw the image from the snapshotter
[image drawAtPoint:CGPointMake(0, 0)];
// now, let''s iterate through the annotations and draw them, too
for (id<MKAnnotation>annotation in self.mapView.annotations)
{
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
if (CGRectContainsPoint(finalImageRect, point)) // this is too conservative, but you get the idea
{
CGPoint pinCenterOffset = pin.centerOffset;
point.x -= pin.bounds.size.width / 2.0;
point.y -= pin.bounds.size.height / 2.0;
point.x += pinCenterOffset.x;
point.y += pinCenterOffset.y;
[pinImage drawAtPoint:point];
}
}
// grab the final image
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// and save it
NSData *data = UIImagePNGRepresentation(finalImage);
[data writeToFile:[self snapshotFilename] atomically:YES];
}];
Para la implementación de MacOS, vea ese video para obtener más información, pero la técnica es básicamente la misma (el mecanismo para crear las imágenes es ligeramente diferente).
Para Swift 3
Aquí hay una versión rápida 3 que modifiqué de este artículo: Renderizar un mapa como una imagen usando MapKit
El siguiente código le permite tomar una instantánea de una región según el Punto (1 coordenada) y la Polilínea (varias coordenadas)
func takeSnapShot() {
let mapSnapshotOptions = MKMapSnapshotOptions()
// Set the region of the map that is rendered. (by one specified coordinate)
// let location = CLLocationCoordinate2DMake(24.78423, 121.01836) // Apple HQ
// let region = MKCoordinateRegionMakeWithDistance(location, 1000, 1000)
// Set the region of the map that is rendered. (by polyline)
// var yourCoordinates = [CLLocationCoordinate2D]() <- initinal this array with your polyline coordinates
let polyLine = MKPolyline(coordinates: &yourCoordinates, count: yourCoordinates.count)
let region = MKCoordinateRegionForMapRect(polyLine.boundingMapRect)
mapSnapshotOptions.region = region
// Set the scale of the image. We''ll just use the scale of the current device, which is 2x scale on Retina screens.
mapSnapshotOptions.scale = UIScreen.main.scale
// Set the size of the image output.
mapSnapshotOptions.size = CGSize(width: IMAGE_VIEW_WIDTH, height: IMAGE_VIEW_HEIGHT)
// Show buildings and Points of Interest on the snapshot
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.showsPointsOfInterest = true
let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
snapShotter.start() { snapshot, error in
guard let snapshot = snapshot else {
return
}
self.imageView.image = snapshot.image
}
}