Merge pull request #978 from aaronschubert0/ASMapNode

[ASMapNode] Greatly improve the internal logic of ASMapNode. Also fixes bug #971
This commit is contained in:
appleguy 2015-12-23 12:55:58 -08:00
commit c968b8dd9e
2 changed files with 66 additions and 57 deletions

View File

@ -12,7 +12,7 @@
@interface ASMapNode : ASImageNode @interface ASMapNode : ASImageNode
/** /**
The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. This property may be set from a background thread before the node is loaded, and will automatically be applied to define the region of the static snapshot (if .liveMap = NO) or the internal MKMapView (otherwise).
*/ */
@property (nonatomic, assign) MKCoordinateRegion region; @property (nonatomic, assign) MKCoordinateRegion region;
@ -22,7 +22,7 @@
@property (nonatomic, readonly) MKMapView *mapView; @property (nonatomic, readonly) MKMapView *mapView;
/** /**
Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. This property may be set on a background thread before the node is loaded, and will automatically be actioned, once the node is loaded.
*/ */
@property (nonatomic, assign, getter=isLiveMap) BOOL liveMap; @property (nonatomic, assign, getter=isLiveMap) BOOL liveMap;

View File

@ -26,6 +26,7 @@
@synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange; @synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange;
@synthesize mapDelegate = _mapDelegate; @synthesize mapDelegate = _mapDelegate;
@synthesize region = _region; @synthesize region = _region;
@synthesize liveMap = _liveMap;
#pragma mark - Lifecycle #pragma mark - Lifecycle
- (instancetype)init - (instancetype)init
@ -37,9 +38,11 @@
self.clipsToBounds = YES; self.clipsToBounds = YES;
_needsMapReloadOnBoundsChange = YES; _needsMapReloadOnBoundsChange = YES;
_liveMap = NO;
_centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid;
_region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(43.432858, 13.183671), MKCoordinateSpanMake(0.2, 0.2));
//Default world-scale view
_region = MKCoordinateRegionForMapRect(MKMapRectWorld);
_options = [[MKMapSnapshotOptions alloc] init]; _options = [[MKMapSnapshotOptions alloc] init];
_options.region = _region; _options.region = _region;
@ -50,26 +53,31 @@
- (void)didLoad - (void)didLoad
{ {
[super didLoad]; [super didLoad];
if ([self wasLiveMapPreviously]) { if (self.isLiveMap) {
self.userInteractionEnabled = YES; self.userInteractionEnabled = YES;
[self addLiveMap]; [self addLiveMap];
} }
} }
- (void)setLayerBacked:(BOOL)layerBacked
{
ASDisplayNodeAssert(!self.isLiveMap, @"ASMapNode can not be layer backed whilst .liveMap = YES, set .liveMap = NO to use layer backing.");
[super setLayerBacked:layerBacked];
}
- (void)fetchData - (void)fetchData
{ {
[super fetchData]; [super fetchData];
if ([self wasLiveMapPreviously]) { if (self.isLiveMap) {
[self addLiveMap]; [self addLiveMap];
} else { } else {
[self setUpSnapshotter];
[self takeSnapshot]; [self takeSnapshot];
} }
} }
- (void)clearFetchedData - (void)clearContents
{ {
[super clearFetchedData]; [super clearContents];
if (self.isLiveMap) { if (self.isLiveMap) {
[self removeLiveMap]; [self removeLiveMap];
} }
@ -79,17 +87,21 @@
- (BOOL)isLiveMap - (BOOL)isLiveMap
{ {
return (_mapView != nil); ASDN::MutexLocker l(_propertyLock);
return _liveMap;
} }
- (void)setLiveMap:(BOOL)liveMap - (void)setLiveMap:(BOOL)liveMap
{ {
liveMap ? [self addLiveMap] : [self removeLiveMap]; ASDisplayNodeAssert(!self.isLayerBacked, @"ASMapNode can not use the interactive map feature whilst .isLayerBacked = YES, set .layerBacked = NO to use the interactive map feature.");
} ASDN::MutexLocker l(_propertyLock);
if (liveMap == _liveMap) {
- (BOOL)wasLiveMapPreviously return;
{ }
return CLLocationCoordinate2DIsValid(_centerCoordinateOfMap); _liveMap = liveMap;
if (self.nodeLoaded) {
liveMap ? [self addLiveMap] : [self removeLiveMap];
}
} }
- (BOOL)needsMapReloadOnBoundsChange - (BOOL)needsMapReloadOnBoundsChange
@ -127,63 +139,62 @@
- (void)takeSnapshot - (void)takeSnapshot
{ {
if (!_snapshotter.isLoading) { if (!_snapshotter) {
[_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { [self setUpSnapshotter];
if (!error) { }
UIImage *image = snapshot.image; [_snapshotter cancel];
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
if (!error) {
UIImage *image = snapshot.image;
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
[image drawAtPoint:CGPointMake(0, 0)]; [image drawAtPoint:CGPointMake(0, 0)];
if (_annotations.count > 0 ) { if (_annotations.count > 0 ) {
// Get a standard annotation view pin. Future implementations should use a custom annotation image property. // Get a standard annotation view pin. Future implementations should use a custom annotation image property.
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
UIImage *pinImage = pin.image; UIImage *pinImage = pin.image;
for (id<MKAnnotation>annotation in _annotations) for (id<MKAnnotation>annotation in _annotations)
{
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
if (CGRectContainsPoint(finalImageRect, point))
{ {
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; CGPoint pinCenterOffset = pin.centerOffset;
if (CGRectContainsPoint(finalImageRect, point)) point.x -= pin.bounds.size.width / 2.0;
{ point.y -= pin.bounds.size.height / 2.0;
CGPoint pinCenterOffset = pin.centerOffset; point.x += pinCenterOffset.x;
point.x -= pin.bounds.size.width / 2.0; point.y += pinCenterOffset.y;
point.y -= pin.bounds.size.height / 2.0; [pinImage drawAtPoint:point];
point.x += pinCenterOffset.x;
point.y += pinCenterOffset.y;
[pinImage drawAtPoint:point];
}
} }
} }
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.image = finalImage;
} }
}];
} UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.image = finalImage;
}
}];
} }
- (void)setUpSnapshotter - (void)setUpSnapshotter
{ {
if (!_snapshotter) { ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar.");
ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar."); _options.size = self.calculatedSize;
_options.size = self.calculatedSize; _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
}
} }
- (void)resetSnapshotter - (void)resetSnapshotter
{ {
if (!_snapshotter.isLoading) { [_snapshotter cancel];
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
}
} }
#pragma mark - Actions #pragma mark - Actions
- (void)addLiveMap - (void)addLiveMap
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
if (!self.isLiveMap) { if (!_mapView) {
__weak ASMapNode *weakSelf = self; __weak ASMapNode *weakSelf = self;
_mapView = [[MKMapView alloc] initWithFrame:CGRectZero]; _mapView = [[MKMapView alloc] initWithFrame:CGRectZero];
_mapView.delegate = weakSelf.mapDelegate; _mapView.delegate = weakSelf.mapDelegate;
@ -194,8 +205,6 @@
if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) { if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) {
[_mapView setCenterCoordinate:_centerCoordinateOfMap]; [_mapView setCenterCoordinate:_centerCoordinateOfMap];
} else {
_centerCoordinateOfMap = _options.region.center;
} }
} }
} }