From fe06f211caac2ed1acecffc34b691d996b35ea98 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 12:13:42 +0000 Subject: [PATCH 01/14] Added an ASMapNode to AsyncDisplayKit --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 + AsyncDisplayKit/ASMapNode.h | 39 ++++ AsyncDisplayKit/ASMapNode.mm | 235 ++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 AsyncDisplayKit/ASMapNode.h create mode 100644 AsyncDisplayKit/ASMapNode.mm diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index cfb767f4..d6257c18 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -211,6 +211,8 @@ 509E68651B3AEDC5009B9150 /* CGRect+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; }; 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; }; + 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; 9B92C8851BC2EB6E00EE46B2 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; }; 9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; }; 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -599,6 +601,8 @@ 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASFlowLayoutController.mm; sourceTree = ""; }; 4640521D1A3F83C40061C0BA /* ASLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutController.h; sourceTree = ""; }; 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; + 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = ""; }; + 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = ""; }; 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutable.h; path = AsyncDisplayKit/Layout/ASStackLayoutable.h; sourceTree = ""; }; 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; @@ -787,6 +791,8 @@ 058D09B1195D04C000B7D73C /* AsyncDisplayKit */ = { isa = PBXGroup; children = ( + 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */, + 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */, 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */, AC6456071B0A335000CF11B8 /* ASCellNode.m */, 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */, @@ -1194,6 +1200,7 @@ ACF6ED4F1B17847A00DA7C62 /* ASStackPositionedLayout.h in Headers */, ACF6ED511B17847A00DA7C62 /* ASStackUnpositionedLayout.h in Headers */, 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */, + 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */, ACF6ED311B17843500DA7C62 /* ASStaticLayoutSpec.h in Headers */, 055F1A3419ABD3E3004DAFF1 /* ASTableView.h in Headers */, 251B8EF71BBB3D690087C538 /* ASCollectionDataController.h in Headers */, @@ -1547,6 +1554,7 @@ AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */, ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */, 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */, + 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */, AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, 205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */, 058D0A13195D050800B7D73C /* ASControlNode.m in Sources */, diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h new file mode 100644 index 00000000..566e6dc0 --- /dev/null +++ b/AsyncDisplayKit/ASMapNode.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#import +#import +@interface ASMapNode : ASControlNode +- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, readonly) ASImageNode *mapImage; +@property (nonatomic, readonly) ASDisplayNode *liveMap; +/** + Whether the map snapshot should turn into a MKMapView when tapped on. Defaults to YES. + */ +@property (nonatomic, assign) BOOL hasLiveMap; +/** + @abstract Explicitly set the size of the map and therefore the size of ASMapNode. Defaults to CGSizeMake(constrainedSize.max.width, 256). + @discussion If the mapSize width or height is greater than the available space, then ASMapNode will take the maximum space available. + @result The current size of the ASMapNode. + */ +@property (nonatomic, assign) CGSize mapSize; +/** + @abstract Whether ASMapNode should automatically request a new map snapshot to correspond to the new node size. Defaults to YES. + @discussion If mapSize is set then this will be set to NO, since the size will be the same in all orientations. + */ +@property (nonatomic, assign) BOOL automaticallyReloadsMapImageOnOrientationChange; +/** + Set the delegate of the MKMapView. + */ +@property (nonatomic, weak) id mapDelegate; +/** + * @discussion This method adds annotations to the static map view and also to the live map view. + * @param annotations An array of objects that conform to the MKAnnotation protocol + */ +- (void)addAnnotations:(NSArray *)annotations; +@end diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm new file mode 100644 index 00000000..869cf0cc --- /dev/null +++ b/AsyncDisplayKit/ASMapNode.mm @@ -0,0 +1,235 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ASMapNode.h" +#import +#import +#import + +@interface ASMapNode() +{ + ASDN::RecursiveMutex _propertyLock; + CGSize _nodeSize; + MKMapSnapshotter *_snapshotter; + MKMapSnapshotOptions *_options; + CGSize _maxSize; + NSArray *_annotations; +} +@end + +@implementation ASMapNode + +@synthesize hasLiveMap = _hasLiveMap; +@synthesize mapSize = _mapSize; +@synthesize automaticallyReloadsMapImageOnOrientationChange = _automaticallyReloadsMapImageOnOrientationChange; +@synthesize mapDelegate = _mapDelegate; + +- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate +{ + if (!(self = [super init])) { + return nil; + } + self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); + _hasLiveMap = YES; + _automaticallyReloadsMapImageOnOrientationChange = YES; + _options = [[MKMapSnapshotOptions alloc] init]; + _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; + + _mapImage = [[ASImageNode alloc]init]; + _mapImage.clipsToBounds = YES; + [self addSubnode:_mapImage]; + [self updateGesture]; + _maxSize = self.bounds.size; + return self; +} + +- (void)addAnnotations:(NSArray *)annotations +{ + ASDN::MutexLocker l(_propertyLock); + if (annotations.count == 0) { + return; + } + _annotations = [annotations copy]; + if (annotations.count != _annotations.count && _mapImage.image) { + // Redraw + [self setNeedsDisplay]; + } +} + +- (void)setUpSnapshotter +{ + if (!_snapshotter) { + _options.size = _nodeSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } +} + +- (BOOL)hasLiveMap +{ + ASDN::MutexLocker l(_propertyLock); + return _hasLiveMap; +} + +- (void)setHasLiveMap:(BOOL)hasLiveMap +{ + ASDN::MutexLocker l(_propertyLock); + if (hasLiveMap == _hasLiveMap) + return; + + _hasLiveMap = hasLiveMap; + [self updateGesture]; +} + +- (CGSize)mapSize +{ + ASDN::MutexLocker l(_propertyLock); + return _mapSize; +} + +- (void)setMapSize:(CGSize)mapSize +{ + ASDN::MutexLocker l(_propertyLock); + if (CGSizeEqualToSize(mapSize,_mapSize)) { + return; + } + _mapSize = mapSize; + _nodeSize = _mapSize; + _automaticallyReloadsMapImageOnOrientationChange = NO; + [self setNeedsLayout]; +} + +- (BOOL)automaticallyReloadsMapImageOnOrientationChange +{ + ASDN::MutexLocker l(_propertyLock); + return _automaticallyReloadsMapImageOnOrientationChange; +} + +- (void)setAutomaticallyReloadsMapImageOnOrientationChange:(BOOL)automaticallyReloadsMapImageOnOrientationChange +{ + ASDN::MutexLocker l(_propertyLock); + if (_automaticallyReloadsMapImageOnOrientationChange == automaticallyReloadsMapImageOnOrientationChange) { + return; + } + _automaticallyReloadsMapImageOnOrientationChange = automaticallyReloadsMapImageOnOrientationChange; + +} + +- (void)updateGesture +{ + _hasLiveMap ? [self addTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside] : [self removeTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside]; +} + +- (void)fetchData +{ + [super fetchData]; + [self setUpSnapshotter]; + [self takeSnapshot]; +} + +- (void)clearFetchedData +{ + [super clearFetchedData]; + if (_liveMap) { + [_liveMap removeFromSupernode]; + _liveMap = nil; + } + _mapImage.image = nil; +} + +- (void)takeSnapshot +{ + if (!_snapshotter.isLoading) { + [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { + if (!error) { + UIImage *image = snapshot.image; + CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); + + // Get a standard annotation view pin. Future implementations should use a custom annotation image property. + MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; + UIImage *pinImage = pin.image; + + UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); + [image drawAtPoint:CGPointMake(0, 0)]; + + for (idannotation in _annotations) + { + CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; + if (CGRectContainsPoint(finalImageRect, point)) + { + 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]; + } + } + UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + _mapImage.image = finalImage; + } + }]; + } +} + +- (void)resetSnapshotter +{ + if (!_snapshotter.isLoading) { + _options.size = _nodeSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } +} + +#pragma mark - Action +- (void)showLiveMap +{ + if (self.isNodeLoaded && !_liveMap) { + _liveMap = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ + MKMapView *mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; + mapView.delegate = _mapDelegate; + [mapView setRegion:_options.region]; + [mapView addAnnotations:_annotations]; + return mapView; + }]; + [self addSubnode:_liveMap]; + _mapImage.image = nil; + } +} + +#pragma mark - Layout +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize +{ + _nodeSize = CGSizeEqualToSize(CGSizeZero, _mapSize) ? CGSizeMake(constrainedSize.width, _options.size.height) : _mapSize; + if (_mapImage) { + [_mapImage calculateSizeThatFits:_nodeSize]; + } + return _nodeSize; +} + +// Layout isn't usually needed in the box model, but since we are making use of MKMapView which is hidden in an ASDisplayNode this is preferred. +- (void)layout +{ + [super layout]; + if (_liveMap) { + MKMapView *mapView = (MKMapView *)_liveMap.view; + mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); + } + else { + _mapImage.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); + if (!CGSizeEqualToSize(_maxSize, self.bounds.size)) { + _mapImage.preferredFrameSize = self.bounds.size; + _maxSize = self.bounds.size; + if (_automaticallyReloadsMapImageOnOrientationChange && _mapImage.image) { + [self resetSnapshotter]; + [self takeSnapshot]; + } + } + } +} + +@end From 46bf49cae7ad98203eecdcb699d94e2143d56283 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 12:18:09 +0000 Subject: [PATCH 02/14] Fix indentation --- AsyncDisplayKit/ASMapNode.h | 1 + AsyncDisplayKit/ASMapNode.mm | 266 +++++++++++++++++------------------ 2 files changed, 134 insertions(+), 133 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index 566e6dc0..4b5ca858 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ + #import #import @interface ASMapNode : ASControlNode diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index 869cf0cc..fdf1067f 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -13,12 +13,12 @@ @interface ASMapNode() { - ASDN::RecursiveMutex _propertyLock; - CGSize _nodeSize; - MKMapSnapshotter *_snapshotter; - MKMapSnapshotOptions *_options; - CGSize _maxSize; - NSArray *_annotations; + ASDN::RecursiveMutex _propertyLock; + CGSize _nodeSize; + MKMapSnapshotter *_snapshotter; + MKMapSnapshotOptions *_options; + CGSize _maxSize; + NSArray *_annotations; } @end @@ -34,202 +34,202 @@ if (!(self = [super init])) { return nil; } - self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _hasLiveMap = YES; - _automaticallyReloadsMapImageOnOrientationChange = YES; - _options = [[MKMapSnapshotOptions alloc] init]; - _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; - - _mapImage = [[ASImageNode alloc]init]; - _mapImage.clipsToBounds = YES; - [self addSubnode:_mapImage]; - [self updateGesture]; - _maxSize = self.bounds.size; - return self; + self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); + _hasLiveMap = YES; + _automaticallyReloadsMapImageOnOrientationChange = YES; + _options = [[MKMapSnapshotOptions alloc] init]; + _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; + + _mapImage = [[ASImageNode alloc]init]; + _mapImage.clipsToBounds = YES; + [self addSubnode:_mapImage]; + [self updateGesture]; + _maxSize = self.bounds.size; + return self; } - (void)addAnnotations:(NSArray *)annotations { - ASDN::MutexLocker l(_propertyLock); - if (annotations.count == 0) { - return; - } - _annotations = [annotations copy]; - if (annotations.count != _annotations.count && _mapImage.image) { - // Redraw - [self setNeedsDisplay]; - } + ASDN::MutexLocker l(_propertyLock); + if (annotations.count == 0) { + return; + } + _annotations = [annotations copy]; + if (annotations.count != _annotations.count && _mapImage.image) { + // Redraw + [self setNeedsDisplay]; + } } - (void)setUpSnapshotter { - if (!_snapshotter) { - _options.size = _nodeSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + if (!_snapshotter) { + _options.size = _nodeSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } } - (BOOL)hasLiveMap { - ASDN::MutexLocker l(_propertyLock); - return _hasLiveMap; + ASDN::MutexLocker l(_propertyLock); + return _hasLiveMap; } - (void)setHasLiveMap:(BOOL)hasLiveMap { - ASDN::MutexLocker l(_propertyLock); - if (hasLiveMap == _hasLiveMap) - return; - - _hasLiveMap = hasLiveMap; - [self updateGesture]; + ASDN::MutexLocker l(_propertyLock); + if (hasLiveMap == _hasLiveMap) + return; + + _hasLiveMap = hasLiveMap; + [self updateGesture]; } - (CGSize)mapSize { - ASDN::MutexLocker l(_propertyLock); - return _mapSize; + ASDN::MutexLocker l(_propertyLock); + return _mapSize; } - (void)setMapSize:(CGSize)mapSize { - ASDN::MutexLocker l(_propertyLock); - if (CGSizeEqualToSize(mapSize,_mapSize)) { - return; - } - _mapSize = mapSize; - _nodeSize = _mapSize; - _automaticallyReloadsMapImageOnOrientationChange = NO; - [self setNeedsLayout]; + ASDN::MutexLocker l(_propertyLock); + if (CGSizeEqualToSize(mapSize,_mapSize)) { + return; + } + _mapSize = mapSize; + _nodeSize = _mapSize; + _automaticallyReloadsMapImageOnOrientationChange = NO; + [self setNeedsLayout]; } - (BOOL)automaticallyReloadsMapImageOnOrientationChange { - ASDN::MutexLocker l(_propertyLock); - return _automaticallyReloadsMapImageOnOrientationChange; + ASDN::MutexLocker l(_propertyLock); + return _automaticallyReloadsMapImageOnOrientationChange; } - (void)setAutomaticallyReloadsMapImageOnOrientationChange:(BOOL)automaticallyReloadsMapImageOnOrientationChange { - ASDN::MutexLocker l(_propertyLock); - if (_automaticallyReloadsMapImageOnOrientationChange == automaticallyReloadsMapImageOnOrientationChange) { - return; - } - _automaticallyReloadsMapImageOnOrientationChange = automaticallyReloadsMapImageOnOrientationChange; - + ASDN::MutexLocker l(_propertyLock); + if (_automaticallyReloadsMapImageOnOrientationChange == automaticallyReloadsMapImageOnOrientationChange) { + return; + } + _automaticallyReloadsMapImageOnOrientationChange = automaticallyReloadsMapImageOnOrientationChange; + } - (void)updateGesture { - _hasLiveMap ? [self addTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside] : [self removeTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside]; + _hasLiveMap ? [self addTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside] : [self removeTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside]; } - (void)fetchData { [super fetchData]; - [self setUpSnapshotter]; - [self takeSnapshot]; + [self setUpSnapshotter]; + [self takeSnapshot]; } - (void)clearFetchedData { - [super clearFetchedData]; - if (_liveMap) { - [_liveMap removeFromSupernode]; - _liveMap = nil; - } - _mapImage.image = nil; + [super clearFetchedData]; + if (_liveMap) { + [_liveMap removeFromSupernode]; + _liveMap = nil; + } + _mapImage.image = nil; } - (void)takeSnapshot { - if (!_snapshotter.isLoading) { - [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { - if (!error) { - UIImage *image = snapshot.image; - CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); - - // Get a standard annotation view pin. Future implementations should use a custom annotation image property. - MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; - UIImage *pinImage = pin.image; - - UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); - [image drawAtPoint:CGPointMake(0, 0)]; - - for (idannotation in _annotations) - { - CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; - if (CGRectContainsPoint(finalImageRect, point)) - { - 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]; - } - } - UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - _mapImage.image = finalImage; - } - }]; - } + if (!_snapshotter.isLoading) { + [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { + if (!error) { + UIImage *image = snapshot.image; + CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); + + // Get a standard annotation view pin. Future implementations should use a custom annotation image property. + MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; + UIImage *pinImage = pin.image; + + UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); + [image drawAtPoint:CGPointMake(0, 0)]; + + for (idannotation in _annotations) + { + CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; + if (CGRectContainsPoint(finalImageRect, point)) + { + 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]; + } + } + UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + _mapImage.image = finalImage; + } + }]; + } } - (void)resetSnapshotter { - if (!_snapshotter.isLoading) { - _options.size = _nodeSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + if (!_snapshotter.isLoading) { + _options.size = _nodeSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } } #pragma mark - Action - (void)showLiveMap { - if (self.isNodeLoaded && !_liveMap) { - _liveMap = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ - MKMapView *mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; - mapView.delegate = _mapDelegate; - [mapView setRegion:_options.region]; - [mapView addAnnotations:_annotations]; - return mapView; - }]; - [self addSubnode:_liveMap]; - _mapImage.image = nil; - } + if (self.isNodeLoaded && !_liveMap) { + _liveMap = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ + MKMapView *mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; + mapView.delegate = _mapDelegate; + [mapView setRegion:_options.region]; + [mapView addAnnotations:_annotations]; + return mapView; + }]; + [self addSubnode:_liveMap]; + _mapImage.image = nil; + } } #pragma mark - Layout - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { - _nodeSize = CGSizeEqualToSize(CGSizeZero, _mapSize) ? CGSizeMake(constrainedSize.width, _options.size.height) : _mapSize; - if (_mapImage) { - [_mapImage calculateSizeThatFits:_nodeSize]; - } - return _nodeSize; + _nodeSize = CGSizeEqualToSize(CGSizeZero, _mapSize) ? CGSizeMake(constrainedSize.width, _options.size.height) : _mapSize; + if (_mapImage) { + [_mapImage calculateSizeThatFits:_nodeSize]; + } + return _nodeSize; } // Layout isn't usually needed in the box model, but since we are making use of MKMapView which is hidden in an ASDisplayNode this is preferred. - (void)layout { - [super layout]; - if (_liveMap) { - MKMapView *mapView = (MKMapView *)_liveMap.view; - mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); - } - else { - _mapImage.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); - if (!CGSizeEqualToSize(_maxSize, self.bounds.size)) { - _mapImage.preferredFrameSize = self.bounds.size; - _maxSize = self.bounds.size; - if (_automaticallyReloadsMapImageOnOrientationChange && _mapImage.image) { - [self resetSnapshotter]; - [self takeSnapshot]; - } - } + [super layout]; + if (_liveMap) { + MKMapView *mapView = (MKMapView *)_liveMap.view; + mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); + } + else { + _mapImage.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); + if (!CGSizeEqualToSize(_maxSize, self.bounds.size)) { + _mapImage.preferredFrameSize = self.bounds.size; + _maxSize = self.bounds.size; + if (_automaticallyReloadsMapImageOnOrientationChange && _mapImage.image) { + [self resetSnapshotter]; + [self takeSnapshot]; + } } + } } @end From 973593f9c4c4f9a6c5d813dc64ae8ca5e2890cc4 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 13:51:23 +0000 Subject: [PATCH 03/14] Try to fix integration tests --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index d6257c18..88ca6c61 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -213,6 +213,9 @@ 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; }; 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; + 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; + 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; + 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9B92C8851BC2EB6E00EE46B2 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; }; 9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; }; 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -603,6 +606,7 @@ 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = ""; }; 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = ""; }; + 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutable.h; path = AsyncDisplayKit/Layout/ASStackLayoutable.h; sourceTree = ""; }; 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; @@ -719,6 +723,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */, B350625F1B0111800018CF92 /* Foundation.framework in Frameworks */, B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */, B350625D1B0111740018CF92 /* Photos.framework in Frameworks */, @@ -778,6 +783,7 @@ 058D09AE195D04C000B7D73C /* Frameworks */ = { isa = PBXGroup; children = ( + 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */, 051943141A1575670030A7D0 /* Photos.framework */, 051943121A1575630030A7D0 /* AssetsLibrary.framework */, 058D09AF195D04C000B7D73C /* Foundation.framework */, @@ -1307,6 +1313,7 @@ CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */, 34EFC7711B701CFF00AD841F /* ASStackLayoutSpec.h in Headers */, 2767E9411BB19BD600EA9B77 /* ASViewController.h in Headers */, + 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */, 044284FE1BAA387800D16268 /* ASStackLayoutSpecUtilities.h in Headers */, 34EFC7751B701D2400AD841F /* ASStackPositionedLayout.h in Headers */, 34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */, @@ -1657,6 +1664,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */, 9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */, 9B92C8851BC2EB6E00EE46B2 /* ASCollectionDataController.mm in Sources */, B350623D1B010EFD0018CF92 /* _ASAsyncTransaction.m in Sources */, From 476bff2bf17e306ab7fc0a57d24e1163ef4a3b8a Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 14:09:48 +0000 Subject: [PATCH 04/14] Link MapKit in static framework. --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 88ca6c61..37bdadd0 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -216,6 +216,8 @@ 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92DD2FE91BF4D4870074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; + 92DD2FEA1BF4D49B0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; 9B92C8851BC2EB6E00EE46B2 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; }; 9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; }; 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -699,6 +701,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FE91BF4D4870074C9DD /* MapKit.framework in Frameworks */, 051943151A1575670030A7D0 /* Photos.framework in Frameworks */, 051943131A1575630030A7D0 /* AssetsLibrary.framework in Frameworks */, 058D09B0195D04C000B7D73C /* Foundation.framework in Frameworks */, @@ -709,6 +712,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FEA1BF4D49B0074C9DD /* MapKit.framework in Frameworks */, 0515EA221A1576A100BA8B9A /* AssetsLibrary.framework in Frameworks */, 0515EA211A15769900BA8B9A /* Photos.framework in Frameworks */, 058D09BE195D04C000B7D73C /* XCTest.framework in Frameworks */, From b35a9bbbb6cc04d83f58557b3de227c0680ced5e Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 14:25:29 +0000 Subject: [PATCH 05/14] Add MapKit to Life Without CocoaPods --- .../Life Without CocoaPods.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smoke-tests/Life Without CocoaPods/Life Without CocoaPods.xcodeproj/project.pbxproj b/smoke-tests/Life Without CocoaPods/Life Without CocoaPods.xcodeproj/project.pbxproj index 3a7e63f9..aaaa4978 100644 --- a/smoke-tests/Life Without CocoaPods/Life Without CocoaPods.xcodeproj/project.pbxproj +++ b/smoke-tests/Life Without CocoaPods/Life Without CocoaPods.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 058969281ABCE1750059CE2A /* libAsyncDisplayKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 058969271ABCE1750059CE2A /* libAsyncDisplayKit.a */; }; 0589692A1ABCE17C0059CE2A /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058969291ABCE17C0059CE2A /* AssetsLibrary.framework */; }; 0589692C1ABCE1820059CE2A /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0589692B1ABCE1820059CE2A /* Photos.framework */; }; + 92DD2FEC1BF4D8BB0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FEB1BF4D8BB0074C9DD /* MapKit.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -32,6 +33,7 @@ 058969271ABCE1750059CE2A /* libAsyncDisplayKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libAsyncDisplayKit.a; path = "../../build/Debug-iphoneos/libAsyncDisplayKit.a"; sourceTree = ""; }; 058969291ABCE17C0059CE2A /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 0589692B1ABCE1820059CE2A /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; + 92DD2FEB1BF4D8BB0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -39,6 +41,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FEC1BF4D8BB0074C9DD /* MapKit.framework in Frameworks */, 0589692C1ABCE1820059CE2A /* Photos.framework in Frameworks */, 0589692A1ABCE17C0059CE2A /* AssetsLibrary.framework in Frameworks */, 058969281ABCE1750059CE2A /* libAsyncDisplayKit.a in Frameworks */, @@ -51,6 +54,7 @@ 058968E61ABCE06E0059CE2A = { isa = PBXGroup; children = ( + 92DD2FEB1BF4D8BB0074C9DD /* MapKit.framework */, 0589692B1ABCE1820059CE2A /* Photos.framework */, 058969291ABCE17C0059CE2A /* AssetsLibrary.framework */, 058969271ABCE1750059CE2A /* libAsyncDisplayKit.a */, From 1b74f8d696d97a01e377e905695b5a17c72c7e48 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 14:27:45 +0000 Subject: [PATCH 06/14] Update ReadMe to mention new MapKit link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a249299..f7743ece 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ pod 'AsyncDisplayKit' (ASDK can also be used as a regular static library: Copy the project to your codebase manually, adding `AsyncDisplayKit.xcodeproj` to your workspace. Add -`libAsyncDisplayKit.a`, AssetsLibrary, and Photos to the "Link Binary With +`libAsyncDisplayKit.a`, MapKit, AssetsLibrary, and Photos to the "Link Binary With Libraries" build phase. Include `-lc++ -ObjC` in your project linker flags.) Import the framework header, or create an [Objective-C bridging From 607be19ce72599bc770b7db493232d507b06f710 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 14:54:29 +0000 Subject: [PATCH 07/14] Update Podspec to require MapKit framework --- AsyncDisplayKit.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit.podspec b/AsyncDisplayKit.podspec index 33237d7b..8404db6b 100644 --- a/AsyncDisplayKit.podspec +++ b/AsyncDisplayKit.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |spec| 'Base/*.{h,m}' ] - spec.frameworks = 'AssetsLibrary' + spec.frameworks = 'AssetsLibrary','MapKit' spec.weak_frameworks = 'Photos' # ASDealloc2MainObject must be compiled with MRR From 156b5866a517e30f05d594b1b689a017dc8374b7 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 14:57:09 +0000 Subject: [PATCH 08/14] Add ASMapNode to main header file. --- AsyncDisplayKit/AsyncDisplayKit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 407d08b0..afbb891d 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -13,6 +13,7 @@ #import #import #import +#import #import From 49c476bdd139e67fa5b1e0ef383e62cca95b35b6 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 12 Nov 2015 15:05:45 +0000 Subject: [PATCH 09/14] Move ASMapNode header into public --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 37bdadd0..3b85e906 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -211,7 +211,7 @@ 509E68651B3AEDC5009B9150 /* CGRect+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; }; 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; }; + 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; @@ -1123,6 +1123,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */, AC026B691BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */, 058D0A71195D05F800B7D73C /* _AS-objc-internal.h in Headers */, 058D0A68195D05EC00B7D73C /* _ASAsyncTransaction.h in Headers */, @@ -1210,7 +1211,6 @@ ACF6ED4F1B17847A00DA7C62 /* ASStackPositionedLayout.h in Headers */, ACF6ED511B17847A00DA7C62 /* ASStackUnpositionedLayout.h in Headers */, 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */, - 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */, ACF6ED311B17843500DA7C62 /* ASStaticLayoutSpec.h in Headers */, 055F1A3419ABD3E3004DAFF1 /* ASTableView.h in Headers */, 251B8EF71BBB3D690087C538 /* ASCollectionDataController.h in Headers */, From 372acd85a42a330f49ecd74f4b975e63a7f012da Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Sun, 15 Nov 2015 16:58:56 +0000 Subject: [PATCH 10/14] Make MapKit a weak framework --- AsyncDisplayKit.podspec | 4 ++-- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit.podspec b/AsyncDisplayKit.podspec index 8404db6b..43123de8 100644 --- a/AsyncDisplayKit.podspec +++ b/AsyncDisplayKit.podspec @@ -21,8 +21,8 @@ Pod::Spec.new do |spec| 'Base/*.{h,m}' ] - spec.frameworks = 'AssetsLibrary','MapKit' - spec.weak_frameworks = 'Photos' + spec.frameworks = 'AssetsLibrary' + spec.weak_frameworks = 'Photos','MapKit' # ASDealloc2MainObject must be compiled with MRR spec.requires_arc = true diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 3b85e906..e1935e29 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ 92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; }; 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 92DD2FE91BF4D4870074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; + 92DD2FE91BF4D4870074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 92DD2FEA1BF4D49B0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; }; 9B92C8851BC2EB6E00EE46B2 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; }; 9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; }; From 863156b2dc5cbd6e1de3b22737ae614a6a470c63 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Mon, 16 Nov 2015 13:48:21 +0000 Subject: [PATCH 11/14] Changed hasLiveMap to liveMap/isLiveMap. Removed internal action handler. Renamed ASDisplayNode liveMap to mapView to avoid naming confusion. --- AsyncDisplayKit/ASMapNode.h | 15 ++++++---- AsyncDisplayKit/ASMapNode.mm | 55 ++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index 4b5ca858..35d63bf2 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -10,13 +10,18 @@ #import @interface ASMapNode : ASControlNode - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate NS_DESIGNATED_INITIALIZER; - -@property (nonatomic, readonly) ASImageNode *mapImage; -@property (nonatomic, readonly) ASDisplayNode *liveMap; /** - Whether the map snapshot should turn into a MKMapView when tapped on. Defaults to YES. + This is the snapshot shot image node, this will be hidden (but not nil) when .liveMap = YES */ -@property (nonatomic, assign) BOOL hasLiveMap; +@property (nonatomic, readonly) ASImageNode *mapImage; +/** + This is the ASDisplayNode that backs the MKMapView. This will be nil if .liveMap = NO. To access the underlying MKMapView, in order to set a delegate for example, use (MKMapView *)mapView.view; + */ +@property (nonatomic, readonly) ASDisplayNode *mapView; +/** + Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. + */ +@property (nonatomic, assign, getter=isLiveMap) BOOL liveMap; /** @abstract Explicitly set the size of the map and therefore the size of ASMapNode. Defaults to CGSizeMake(constrainedSize.max.width, 256). @discussion If the mapSize width or height is greater than the available space, then ASMapNode will take the maximum space available. diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index fdf1067f..d60171a9 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -24,7 +24,7 @@ @implementation ASMapNode -@synthesize hasLiveMap = _hasLiveMap; +@synthesize liveMap = _liveMap; @synthesize mapSize = _mapSize; @synthesize automaticallyReloadsMapImageOnOrientationChange = _automaticallyReloadsMapImageOnOrientationChange; @synthesize mapDelegate = _mapDelegate; @@ -35,15 +35,14 @@ return nil; } self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _hasLiveMap = YES; _automaticallyReloadsMapImageOnOrientationChange = YES; + _liveMap = NO; + _options = [[MKMapSnapshotOptions alloc] init]; _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; - _mapImage = [[ASImageNode alloc]init]; _mapImage.clipsToBounds = YES; [self addSubnode:_mapImage]; - [self updateGesture]; _maxSize = self.bounds.size; return self; } @@ -69,20 +68,18 @@ } } -- (BOOL)hasLiveMap +- (BOOL)isLiveMap { ASDN::MutexLocker l(_propertyLock); - return _hasLiveMap; + return _liveMap; } -- (void)setHasLiveMap:(BOOL)hasLiveMap +- (void)setLiveMap:(BOOL)liveMap { ASDN::MutexLocker l(_propertyLock); - if (hasLiveMap == _hasLiveMap) - return; - - _hasLiveMap = hasLiveMap; - [self updateGesture]; + if (liveMap == _liveMap) return; + _liveMap = liveMap; + liveMap ? [self addLiveMap] : [self removeLiveMap]; } - (CGSize)mapSize @@ -119,11 +116,6 @@ } -- (void)updateGesture -{ - _hasLiveMap ? [self addTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside] : [self removeTarget:self action:@selector(showLiveMap) forControlEvents:ASControlNodeEventTouchUpInside]; -} - - (void)fetchData { [super fetchData]; @@ -134,9 +126,9 @@ - (void)clearFetchedData { [super clearFetchedData]; - if (_liveMap) { - [_liveMap removeFromSupernode]; - _liveMap = nil; + if (_mapView) { + [_mapView removeFromSupernode]; + _mapView = nil; } _mapImage.image = nil; } @@ -186,18 +178,27 @@ } #pragma mark - Action -- (void)showLiveMap +- (void)addLiveMap { - if (self.isNodeLoaded && !_liveMap) { - _liveMap = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ + if (self.isNodeLoaded && !_mapView) { + _mapView = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ MKMapView *mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; mapView.delegate = _mapDelegate; [mapView setRegion:_options.region]; [mapView addAnnotations:_annotations]; return mapView; }]; - [self addSubnode:_liveMap]; - _mapImage.image = nil; + [self addSubnode:_mapView]; + _mapImage.hidden = YES; + } +} + +- (void)removeLiveMap +{ + if (_mapView) { + [_mapView removeFromSupernode]; + _mapView = nil; + _mapImage.hidden = NO; } } @@ -215,8 +216,8 @@ - (void)layout { [super layout]; - if (_liveMap) { - MKMapView *mapView = (MKMapView *)_liveMap.view; + if (_mapView) { + MKMapView *mapView = (MKMapView *)_mapView.view; mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); } else { From 79b4c9574933c5a5c46563db2ac55d894bded7e2 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 3 Dec 2015 11:22:05 +0000 Subject: [PATCH 12/14] Substantially improved ASMapNode and made it a lot clearer and less complex internally. --- AsyncDisplayKit/ASMapNode.h | 32 ++-- AsyncDisplayKit/ASMapNode.mm | 162 ++++++++---------- .../Kittens/Sample.xcodeproj/project.pbxproj | 16 ++ examples/Kittens/Sample/KittenNode.mm | 30 +++- 4 files changed, 127 insertions(+), 113 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index 35d63bf2..e5fcbd49 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -8,38 +8,36 @@ #import #import -@interface ASMapNode : ASControlNode + +@interface ASMapNode : ASImageNode + - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate NS_DESIGNATED_INITIALIZER; + /** - This is the snapshot shot image node, this will be hidden (but not nil) when .liveMap = YES + This is the MKMapView that is the live map part of ASMapNode. This will be nil if .liveMap = NO. Note, MKMapView is *not* thread-safe. */ -@property (nonatomic, readonly) ASImageNode *mapImage; -/** - This is the ASDisplayNode that backs the MKMapView. This will be nil if .liveMap = NO. To access the underlying MKMapView, in order to set a delegate for example, use (MKMapView *)mapView.view; - */ -@property (nonatomic, readonly) ASDisplayNode *mapView; +@property (nonatomic, readonly) MKMapView *mapView; + /** Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. */ @property (nonatomic, assign, getter=isLiveMap) BOOL liveMap; -/** - @abstract Explicitly set the size of the map and therefore the size of ASMapNode. Defaults to CGSizeMake(constrainedSize.max.width, 256). - @discussion If the mapSize width or height is greater than the available space, then ASMapNode will take the maximum space available. - @result The current size of the ASMapNode. - */ -@property (nonatomic, assign) CGSize mapSize; + /** @abstract Whether ASMapNode should automatically request a new map snapshot to correspond to the new node size. Defaults to YES. @discussion If mapSize is set then this will be set to NO, since the size will be the same in all orientations. */ -@property (nonatomic, assign) BOOL automaticallyReloadsMapImageOnOrientationChange; +@property (nonatomic, assign) BOOL needsMapReloadOnBoundsChange; + /** - Set the delegate of the MKMapView. + Set the delegate of the MKMapView. This can be set even before mapView is created and will be set on the map in the case that the liveMap mode is engaged. */ @property (nonatomic, weak) id mapDelegate; + /** - * @discussion This method adds annotations to the static map view and also to the live map view. + * @discussion This method set the annotations of the static map view and also to the live map view. Passing an empty array clears the map of any annotations. * @param annotations An array of objects that conform to the MKAnnotation protocol */ -- (void)addAnnotations:(NSArray *)annotations; +- (void)setAnnotations:(NSArray *)annotations; + @end diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index d60171a9..31100036 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -14,19 +14,18 @@ @interface ASMapNode() { ASDN::RecursiveMutex _propertyLock; - CGSize _nodeSize; MKMapSnapshotter *_snapshotter; MKMapSnapshotOptions *_options; - CGSize _maxSize; NSArray *_annotations; + ASDisplayNode *_mapNode; + CLLocationCoordinate2D _centerCoordinateOfMap; } @end @implementation ASMapNode @synthesize liveMap = _liveMap; -@synthesize mapSize = _mapSize; -@synthesize automaticallyReloadsMapImageOnOrientationChange = _automaticallyReloadsMapImageOnOrientationChange; +@synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange; @synthesize mapDelegate = _mapDelegate; - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate @@ -35,26 +34,23 @@ return nil; } self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - _automaticallyReloadsMapImageOnOrientationChange = YES; + self.clipsToBounds = YES; + + _needsMapReloadOnBoundsChange = YES; _liveMap = NO; + _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; _options = [[MKMapSnapshotOptions alloc] init]; _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; - _mapImage = [[ASImageNode alloc]init]; - _mapImage.clipsToBounds = YES; - [self addSubnode:_mapImage]; - _maxSize = self.bounds.size; + return self; } -- (void)addAnnotations:(NSArray *)annotations +- (void)setAnnotations:(NSArray *)annotations { ASDN::MutexLocker l(_propertyLock); - if (annotations.count == 0) { - return; - } _annotations = [annotations copy]; - if (annotations.count != _annotations.count && _mapImage.image) { + if (annotations.count != _annotations.count) { // Redraw [self setNeedsDisplay]; } @@ -63,8 +59,9 @@ - (void)setUpSnapshotter { if (!_snapshotter) { - _options.size = _nodeSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + 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; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; } } @@ -77,60 +74,42 @@ - (void)setLiveMap:(BOOL)liveMap { ASDN::MutexLocker l(_propertyLock); - if (liveMap == _liveMap) return; + if (liveMap == _liveMap) { + return; + } _liveMap = liveMap; liveMap ? [self addLiveMap] : [self removeLiveMap]; } -- (CGSize)mapSize + +- (BOOL)needsMapReloadOnBoundsChange { ASDN::MutexLocker l(_propertyLock); - return _mapSize; + return _needsMapReloadOnBoundsChange; } -- (void)setMapSize:(CGSize)mapSize +- (void)setNeedsMapReloadOnBoundsChange:(BOOL)needsMapReloadOnBoundsChange { ASDN::MutexLocker l(_propertyLock); - if (CGSizeEqualToSize(mapSize,_mapSize)) { - return; - } - _mapSize = mapSize; - _nodeSize = _mapSize; - _automaticallyReloadsMapImageOnOrientationChange = NO; - [self setNeedsLayout]; -} - -- (BOOL)automaticallyReloadsMapImageOnOrientationChange -{ - ASDN::MutexLocker l(_propertyLock); - return _automaticallyReloadsMapImageOnOrientationChange; -} - -- (void)setAutomaticallyReloadsMapImageOnOrientationChange:(BOOL)automaticallyReloadsMapImageOnOrientationChange -{ - ASDN::MutexLocker l(_propertyLock); - if (_automaticallyReloadsMapImageOnOrientationChange == automaticallyReloadsMapImageOnOrientationChange) { - return; - } - _automaticallyReloadsMapImageOnOrientationChange = automaticallyReloadsMapImageOnOrientationChange; - + _needsMapReloadOnBoundsChange = needsMapReloadOnBoundsChange; } - (void)fetchData { [super fetchData]; - [self setUpSnapshotter]; - [self takeSnapshot]; + if (_liveMap && !_mapNode) { + [self addLiveMap]; + } + else { + [self setUpSnapshotter]; + [self takeSnapshot]; + } } - (void)clearFetchedData { [super clearFetchedData]; - if (_mapView) { - [_mapView removeFromSupernode]; - _mapView = nil; - } - _mapImage.image = nil; + [self removeLiveMap]; } - (void)takeSnapshot @@ -141,29 +120,31 @@ UIImage *image = snapshot.image; CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); - // Get a standard annotation view pin. Future implementations should use a custom annotation image property. - MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; - UIImage *pinImage = pin.image; - UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); [image drawAtPoint:CGPointMake(0, 0)]; - for (idannotation in _annotations) - { - CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; - if (CGRectContainsPoint(finalImageRect, point)) + if (_annotations.count > 0 ) { + // Get a standard annotation view pin. Future implementations should use a custom annotation image property. + MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; + UIImage *pinImage = pin.image; + for (idannotation in _annotations) { - 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]; + CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; + if (CGRectContainsPoint(finalImageRect, point)) + { + 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]; + } } } + UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - _mapImage.image = finalImage; + self.image = finalImage; } }]; } @@ -172,7 +153,7 @@ - (void)resetSnapshotter { if (!_snapshotter.isLoading) { - _options.size = _nodeSize; + _options.size = self.calculatedSize; _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; } } @@ -180,52 +161,45 @@ #pragma mark - Action - (void)addLiveMap { - if (self.isNodeLoaded && !_mapView) { - _mapView = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ - MKMapView *mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; - mapView.delegate = _mapDelegate; - [mapView setRegion:_options.region]; - [mapView addAnnotations:_annotations]; - return mapView; + if (self.isNodeLoaded && !_mapNode) { + _mapNode = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ + _mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; + _mapView.delegate = _mapDelegate; + [_mapView setRegion:_options.region]; + [_mapView addAnnotations:_annotations]; + return _mapView; }]; - [self addSubnode:_mapView]; - _mapImage.hidden = YES; + [self addSubnode:_mapNode]; + + if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) { + [_mapView setCenterCoordinate:_centerCoordinateOfMap]; + } } } - (void)removeLiveMap { - if (_mapView) { - [_mapView removeFromSupernode]; + if (_mapNode) { + _centerCoordinateOfMap = _mapView.centerCoordinate; + [_mapNode removeFromSupernode]; _mapView = nil; - _mapImage.hidden = NO; + _mapNode = nil; } + self.image = nil; } #pragma mark - Layout -- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize -{ - _nodeSize = CGSizeEqualToSize(CGSizeZero, _mapSize) ? CGSizeMake(constrainedSize.width, _options.size.height) : _mapSize; - if (_mapImage) { - [_mapImage calculateSizeThatFits:_nodeSize]; - } - return _nodeSize; -} - // Layout isn't usually needed in the box model, but since we are making use of MKMapView which is hidden in an ASDisplayNode this is preferred. - (void)layout { [super layout]; if (_mapView) { - MKMapView *mapView = (MKMapView *)_mapView.view; - mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); + _mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); } else { - _mapImage.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); - if (!CGSizeEqualToSize(_maxSize, self.bounds.size)) { - _mapImage.preferredFrameSize = self.bounds.size; - _maxSize = self.bounds.size; - if (_automaticallyReloadsMapImageOnOrientationChange && _mapImage.image) { + // If our bounds.size is different from our current snapshot size, then let's request a new image from MKMapSnapshotter. + if (!CGSizeEqualToSize(_options.size, self.bounds.size)) { + if (_needsMapReloadOnBoundsChange && self.image) { [self resetSnapshotter]; [self takeSnapshot]; } diff --git a/examples/Kittens/Sample.xcodeproj/project.pbxproj b/examples/Kittens/Sample.xcodeproj/project.pbxproj index ddfd8840..e70aa778 100644 --- a/examples/Kittens/Sample.xcodeproj/project.pbxproj +++ b/examples/Kittens/Sample.xcodeproj/project.pbxproj @@ -128,6 +128,7 @@ 05E2127E19D4DB510098F589 /* Frameworks */, 05E2127F19D4DB510098F589 /* Resources */, F012A6F39E0149F18F564F50 /* Copy Pods Resources */, + 860D1494A00C2E990C93A4D9 /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -184,6 +185,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 860D1494A00C2E990C93A4D9 /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index adc656aa..14431395 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -29,6 +29,7 @@ static const CGFloat kInnerPadding = 10.0f; ASNetworkImageNode *_imageNode; ASTextNode *_textNode; ASDisplayNode *_divider; + ASMapNode *_map; BOOL _isImageEnlarged; BOOL _swappedTextAndImage; } @@ -88,6 +89,22 @@ static const CGFloat kInnerPadding = 10.0f; // _imageNode.contentMode = UIViewContentModeCenter; [_imageNode addTarget:self action:@selector(toggleNodesSwap) forControlEvents:ASControlNodeEventTouchUpInside]; [self addSubnode:_imageNode]; + + MKPointAnnotation *point1 = [[MKPointAnnotation alloc]init]; + point1.coordinate = CLLocationCoordinate2DMake(55.864237, -4.251806); + point1.title = @"Best fish & chip shop"; + point1.subtitle = @"Everrrrrr"; + + + MKPointAnnotation *point2 = [[MKPointAnnotation alloc]init]; + point2.coordinate = CLLocationCoordinate2DMake(55.861, -4.251806); + point2.title = @"The 2nd Best fish & chip shop"; + point2.subtitle = @"Everrrrrr"; + + _map = [[ASMapNode alloc]initWithCoordinate:CLLocationCoordinate2DMake(55.864237, -4.251806)]; + [_map addTarget:self action:@selector(makeMapInteractive) forControlEvents:ASControlNodeEventTouchUpInside]; + [_map setAnnotations:@[point1,point2]]; + [self addSubnode:_map]; // lorem ipsum text, plus some nice styling _textNode = [[ASTextNode alloc] init]; @@ -131,16 +148,25 @@ static const CGFloat kInnerPadding = 10.0f; NSParagraphStyleAttributeName: style }; } +- (void)makeMapInteractive +{ + [_map setLiveMap:YES]; +} + #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; + + ASRatioLayoutSpec *ratioSpec = [[ASRatioLayoutSpec alloc]init]; + ratioSpec.ratio = 0.5; + ratioSpec.child = _map; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; - stackSpec.direction = ASStackLayoutDirectionHorizontal; + stackSpec.direction = ASStackLayoutDirectionVertical; stackSpec.spacing = kInnerPadding; - [stackSpec setChildren:!_swappedTextAndImage ? @[_imageNode, _textNode] : @[_textNode, _imageNode]]; + [stackSpec setChildren:!_swappedTextAndImage ? @[ratioSpec,_imageNode, _textNode] : @[ratioSpec,_textNode, _imageNode]]; ASInsetLayoutSpec *insetSpec = [[ASInsetLayoutSpec alloc] init]; insetSpec.insets = UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding); From 945e6fdb4454a017d5850e0da1a0ad8c2106670d Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 3 Dec 2015 11:28:10 +0000 Subject: [PATCH 13/14] Revert accidental changes to Kittens example. Apologies @nguyenhuy ! --- .../Kittens/Sample.xcodeproj/project.pbxproj | 16 ---------- examples/Kittens/Sample/KittenNode.mm | 30 ++----------------- 2 files changed, 2 insertions(+), 44 deletions(-) diff --git a/examples/Kittens/Sample.xcodeproj/project.pbxproj b/examples/Kittens/Sample.xcodeproj/project.pbxproj index e70aa778..ddfd8840 100644 --- a/examples/Kittens/Sample.xcodeproj/project.pbxproj +++ b/examples/Kittens/Sample.xcodeproj/project.pbxproj @@ -128,7 +128,6 @@ 05E2127E19D4DB510098F589 /* Frameworks */, 05E2127F19D4DB510098F589 /* Resources */, F012A6F39E0149F18F564F50 /* Copy Pods Resources */, - 860D1494A00C2E990C93A4D9 /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -185,21 +184,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 860D1494A00C2E990C93A4D9 /* Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/examples/Kittens/Sample/KittenNode.mm b/examples/Kittens/Sample/KittenNode.mm index 14431395..adc656aa 100644 --- a/examples/Kittens/Sample/KittenNode.mm +++ b/examples/Kittens/Sample/KittenNode.mm @@ -29,7 +29,6 @@ static const CGFloat kInnerPadding = 10.0f; ASNetworkImageNode *_imageNode; ASTextNode *_textNode; ASDisplayNode *_divider; - ASMapNode *_map; BOOL _isImageEnlarged; BOOL _swappedTextAndImage; } @@ -89,22 +88,6 @@ static const CGFloat kInnerPadding = 10.0f; // _imageNode.contentMode = UIViewContentModeCenter; [_imageNode addTarget:self action:@selector(toggleNodesSwap) forControlEvents:ASControlNodeEventTouchUpInside]; [self addSubnode:_imageNode]; - - MKPointAnnotation *point1 = [[MKPointAnnotation alloc]init]; - point1.coordinate = CLLocationCoordinate2DMake(55.864237, -4.251806); - point1.title = @"Best fish & chip shop"; - point1.subtitle = @"Everrrrrr"; - - - MKPointAnnotation *point2 = [[MKPointAnnotation alloc]init]; - point2.coordinate = CLLocationCoordinate2DMake(55.861, -4.251806); - point2.title = @"The 2nd Best fish & chip shop"; - point2.subtitle = @"Everrrrrr"; - - _map = [[ASMapNode alloc]initWithCoordinate:CLLocationCoordinate2DMake(55.864237, -4.251806)]; - [_map addTarget:self action:@selector(makeMapInteractive) forControlEvents:ASControlNodeEventTouchUpInside]; - [_map setAnnotations:@[point1,point2]]; - [self addSubnode:_map]; // lorem ipsum text, plus some nice styling _textNode = [[ASTextNode alloc] init]; @@ -148,25 +131,16 @@ static const CGFloat kInnerPadding = 10.0f; NSParagraphStyleAttributeName: style }; } -- (void)makeMapInteractive -{ - [_map setLiveMap:YES]; -} - #if UseAutomaticLayout - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { _imageNode.preferredFrameSize = _isImageEnlarged ? CGSizeMake(2.0 * kImageSize, 2.0 * kImageSize) : CGSizeMake(kImageSize, kImageSize); _textNode.flexShrink = YES; - - ASRatioLayoutSpec *ratioSpec = [[ASRatioLayoutSpec alloc]init]; - ratioSpec.ratio = 0.5; - ratioSpec.child = _map; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; - stackSpec.direction = ASStackLayoutDirectionVertical; + stackSpec.direction = ASStackLayoutDirectionHorizontal; stackSpec.spacing = kInnerPadding; - [stackSpec setChildren:!_swappedTextAndImage ? @[ratioSpec,_imageNode, _textNode] : @[ratioSpec,_textNode, _imageNode]]; + [stackSpec setChildren:!_swappedTextAndImage ? @[_imageNode, _textNode] : @[_textNode, _imageNode]]; ASInsetLayoutSpec *insetSpec = [[ASInsetLayoutSpec alloc] init]; insetSpec.insets = UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding); From e1b50ce77ac29fcf963576800e8271a7356a7d02 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 3 Dec 2015 14:23:27 +0000 Subject: [PATCH 14/14] Fix merge conflicts --- AsyncDisplayKit.xcodeproj/project.pbxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 592ac099..02312203 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -657,7 +657,7 @@ 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASFlowLayoutController.h; sourceTree = ""; }; 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASFlowLayoutController.mm; sourceTree = ""; }; 4640521D1A3F83C40061C0BA /* ASLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutController.h; sourceTree = ""; }; - 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; + 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = ""; }; 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = ""; }; 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; @@ -1199,6 +1199,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */, 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */, AC026B691BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */, 058D0A71195D05F800B7D73C /* _AS-objc-internal.h in Headers */,