Снимок MKMapView в iOS7
Я пытаюсь создать снимок приложения MKMapView в iOS7 так же, как это рекомендуется везде для предыдущих версий iOS:
- (UIImage*) renderMapViewToImage
{
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, NO, 0.0);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Однако возвращаемое изображение представляет собой черный прямоугольник с синей точкой текущего местоположения сверху. Я также пытался использовать разные подслои mapView, но результат всегда одинаков.
Кто-нибудь знает, как делать снимки MKMapView в iOS7?
3 ответа
Ты можешь использовать MKMapSnapshotter
и захватить image
из полученного MKMapSnapshot
, Смотрите обсуждение этого видео-сессии WWDC 2013, " Перевод карты в перспективу".
Например:
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];
}];
Сказав это, renderInContext
Решение все еще работает для меня. Есть заметки о том, чтобы делать это только в основной очереди в iOS7, но, похоже, все еще работает. Но MKMapSnapshotter
Похоже, более подходящее решение для iOS7.
Если вы хотите включить некоторые аннотации в снимок, вы должны нарисовать их вручную (!). Это обсуждается в некоторых деталях в конце комплекта Putting Map Kit в перспективе. Я должен сказать, что это одна из наименее элегантных реализаций, которые я когда-либо видел в советах Apple. В любом случае, в iOS это может выглядеть так:
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];
}];
Для реализации MacOS, смотрите это видео для получения дополнительной информации, но техника в основном та же (механизм создания изображений немного отличается).
Для iOS 10 и выше вы можете использовать UIGraphicsImageRenderer
класс для рендеринга любого вида изображения (на тот случай, если вы не хотите использовать MKMapSnapshotter
, так как я использую MapBox
).
let render = UIGraphicsImageRenderer(size: self.mapView.bounds.size)
let image = render.image { ctx in
self.mapView.drawHierarchy(in: self.mapView.bounds, afterScreenUpdates: true)
}
Результат:
Для Swift 3
Вот версия Swift 3, которую я модифицировал из этой статьи: Визуализация карты как изображения с использованием MapKit
Следующий код позволяет снимать область на основе точек (1 координата) и полилинии (несколько координат)
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
}
}