From 1dfb8fac67d0428d7be7fcecb7620892fd4c2542 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Tue, 8 Dec 2015 10:37:00 +0000 Subject: [PATCH 01/16] Changed init method, as well as further clean up to get ASMapNode ready for 2.0 --- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 +- AsyncDisplayKit/ASMapNode.h | 2 +- AsyncDisplayKit/ASMapNode.mm | 97 ++++++++++++++--------- 3 files changed, 60 insertions(+), 41 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 91e8c8b36b..7ec37737ed 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -517,7 +517,7 @@ 057D02C51AC0A66700C7AC3C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 057D02C61AC0A66700C7AC3C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 0587F9BB1A7309ED00AFF0BA /* ASEditableTextNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEditableTextNode.h; sourceTree = ""; }; - 0587F9BC1A7309ED00AFF0BA /* ASEditableTextNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASEditableTextNode.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 0587F9BC1A7309ED00AFF0BA /* ASEditableTextNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASEditableTextNode.mm; sourceTree = ""; }; 058D09AC195D04C000B7D73C /* libAsyncDisplayKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAsyncDisplayKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; 058D09AF195D04C000B7D73C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 058D09B3195D04C000B7D73C /* AsyncDisplayKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AsyncDisplayKit-Prefix.pch"; sourceTree = ""; }; diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index e5fcbd4921..d47a1343eb 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -11,7 +11,7 @@ @interface ASMapNode : ASImageNode -- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithRegion:(MKCoordinateRegion)region NS_DESIGNATED_INITIALIZER; /** 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. diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index 311000362e..39a24a1907 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -28,7 +28,8 @@ @synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange; @synthesize mapDelegate = _mapDelegate; -- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate +#pragma mark - Lifecycle +- (instancetype)initWithRegion:(MKCoordinateRegion)region { if (!(self = [super init])) { return nil; @@ -41,30 +42,40 @@ _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; _options = [[MKMapSnapshotOptions alloc] init]; - _options.region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);; + _options.region = region; return self; } -- (void)setAnnotations:(NSArray *)annotations +- (void)didLoad { - ASDN::MutexLocker l(_propertyLock); - _annotations = [annotations copy]; - if (annotations.count != _annotations.count) { - // Redraw - [self setNeedsDisplay]; - } + [super didLoad]; + if (self.isLiveMap && !_mapNode) { + self.userInteractionEnabled = YES; + [self addLiveMap]; + } } -- (void)setUpSnapshotter +- (void)fetchData { - 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."); - _options.size = self.calculatedSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + [super fetchData]; + if (_liveMap && !_mapNode) { + [self addLiveMap]; + } + else { + [self setUpSnapshotter]; + [self takeSnapshot]; + } } +- (void)clearFetchedData +{ + [super clearFetchedData]; + [self removeLiveMap]; +} + +#pragma mark - Settings + - (BOOL)isLiveMap { ASDN::MutexLocker l(_propertyLock); @@ -94,23 +105,8 @@ _needsMapReloadOnBoundsChange = needsMapReloadOnBoundsChange; } -- (void)fetchData -{ - [super fetchData]; - if (_liveMap && !_mapNode) { - [self addLiveMap]; - } - else { - [self setUpSnapshotter]; - [self takeSnapshot]; - } -} -- (void)clearFetchedData -{ - [super clearFetchedData]; - [self removeLiveMap]; -} +#pragma mark - Snapshotter - (void)takeSnapshot { @@ -150,23 +146,33 @@ } } +- (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."); + _options.size = self.calculatedSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } +} + - (void)resetSnapshotter { if (!_snapshotter.isLoading) { - _options.size = self.calculatedSize; _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; } } -#pragma mark - Action +#pragma mark - Actions - (void)addLiveMap { if (self.isNodeLoaded && !_mapNode) { - _mapNode = [[ASDisplayNode alloc]initWithViewBlock:^UIView *{ - _mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height)]; + __weak ASMapNode *weakSelf = self; + _mapNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ + _mapView = [[MKMapView alloc] initWithFrame:CGRectZero]; _mapView.delegate = _mapDelegate; [_mapView setRegion:_options.region]; [_mapView addAnnotations:_annotations]; + [weakSelf setNeedsLayout]; return _mapView; }]; [self addSubnode:_mapNode]; @@ -185,9 +191,23 @@ _mapView = nil; _mapNode = nil; } - self.image = nil; } +- (void)setAnnotations:(NSArray *)annotations +{ + ASDN::MutexLocker l(_propertyLock); + _annotations = [annotations copy]; + if (annotations.count != _annotations.count) { + // Redraw + [self setNeedsDisplay]; + if (_mapView) { + [_mapView removeAnnotations:_mapView.annotations]; + [_mapView addAnnotations:annotations]; + } + } +} + + #pragma mark - Layout // 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 @@ -198,11 +218,10 @@ } else { // 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) { + if (!CGSizeEqualToSize(_options.size, self.bounds.size) && _needsMapReloadOnBoundsChange) { + _options.size = self.bounds.size; [self resetSnapshotter]; [self takeSnapshot]; - } } } } From e4ca0e3ccf443bf37d31de7f3d87bd5d74ef89a7 Mon Sep 17 00:00:00 2001 From: Samuel Hsiung Date: Fri, 11 Dec 2015 18:53:10 -0800 Subject: [PATCH 02/16] make ASEditableTextNode's textView clip to bounds --- AsyncDisplayKit/ASEditableTextNode.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index d8da46498b..13554d88e5 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -124,7 +124,6 @@ textView.opaque = NO; } textView.textContainerInset = self.textContainerInset; - textView.clipsToBounds = NO; // We don't want selection handles cut off. }; // Create and configure the placeholder text view. From 50f652a5b329d97eec03c3738686d4fbb73373a6 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Mon, 14 Dec 2015 10:22:37 +0000 Subject: [PATCH 03/16] Fix indendation --- AsyncDisplayKit/ASMapNode.mm | 70 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index 39a24a1907..bf5e3570ae 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -36,11 +36,11 @@ } self.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); self.clipsToBounds = YES; - + _needsMapReloadOnBoundsChange = YES; _liveMap = NO; _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; - + _options = [[MKMapSnapshotOptions alloc] init]; _options.region = region; @@ -49,29 +49,28 @@ - (void)didLoad { - [super didLoad]; - if (self.isLiveMap && !_mapNode) { - self.userInteractionEnabled = YES; - [self addLiveMap]; - } + [super didLoad]; + if (self.isLiveMap && !_mapNode) { + self.userInteractionEnabled = YES; + [self addLiveMap]; + } } - (void)fetchData { - [super fetchData]; - if (_liveMap && !_mapNode) { - [self addLiveMap]; - } - else { - [self setUpSnapshotter]; - [self takeSnapshot]; - } + [super fetchData]; + if (_liveMap && !_mapNode) { + [self addLiveMap]; + } else { + [self setUpSnapshotter]; + [self takeSnapshot]; + } } - (void)clearFetchedData { - [super clearFetchedData]; - [self removeLiveMap]; + [super clearFetchedData]; + [self removeLiveMap]; } #pragma mark - Settings @@ -148,11 +147,11 @@ - (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."); - _options.size = self.calculatedSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + 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."); + _options.size = self.calculatedSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; + } } - (void)resetSnapshotter @@ -195,16 +194,16 @@ - (void)setAnnotations:(NSArray *)annotations { - ASDN::MutexLocker l(_propertyLock); - _annotations = [annotations copy]; - if (annotations.count != _annotations.count) { - // Redraw - [self setNeedsDisplay]; - if (_mapView) { - [_mapView removeAnnotations:_mapView.annotations]; - [_mapView addAnnotations:annotations]; - } + ASDN::MutexLocker l(_propertyLock); + _annotations = [annotations copy]; + if (annotations.count != _annotations.count) { + // Redraw + [self setNeedsDisplay]; + if (_mapView) { + [_mapView removeAnnotations:_mapView.annotations]; + [_mapView addAnnotations:annotations]; } + } } @@ -215,13 +214,12 @@ [super layout]; if (_mapView) { _mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); - } - else { + } else { // 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) && _needsMapReloadOnBoundsChange) { - _options.size = self.bounds.size; - [self resetSnapshotter]; - [self takeSnapshot]; + _options.size = self.bounds.size; + [self resetSnapshotter]; + [self takeSnapshot]; } } } From f9d476e1705886bff5253142bcf0612155ad9adb Mon Sep 17 00:00:00 2001 From: Samuel Hsiung Date: Tue, 15 Dec 2015 10:09:03 -0800 Subject: [PATCH 04/16] Fix ASTextNode truncated size calculation ignoring attributes in the last line --- AsyncDisplayKit-Prefix.gcda | Bin 656 -> 656 bytes AsyncDisplayKit/ASTextNode.mm | 12 +++++++++++- .../TextKit/ASTextKitTailTruncater.mm | 1 + AsyncDisplayKitTests/ASTextNodeTests.m | 14 ++++++++++++-- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit-Prefix.gcda b/AsyncDisplayKit-Prefix.gcda index 450c9162de2c4e70a2d89835d0e42d57404c1766..72e86999c9372666b6b78fd16af20e83deaa4c29 100644 GIT binary patch delta 52 zcmbQhI)Qb91PjA|r5h7vTv)4gCBE=Yl$D%VXT)0UqTD3}VxMzjO Date: Tue, 15 Dec 2015 14:41:37 -0500 Subject: [PATCH 05/16] Fixed ASTextKit CoreText attributes bug which was incorrectly reading a NSParagraphStyle as CTParagraphStyleRef --- .../TextKit/ASTextKitCoreTextAdditions.m | 2 +- .../ASTextKitCoreTextAdditionsTests.m | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.m b/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.m index e317559572..d2f7465349 100644 --- a/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.m +++ b/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.m @@ -88,7 +88,7 @@ NSDictionary *NSAttributedStringAttributesForCoreTextAttributes(NSDictionary *co cleanAttributes[NSForegroundColorAttributeName] = [UIColor colorWithCGColor:(CGColorRef)coreTextValue]; } // kCTParagraphStyleAttributeName -> NSParagraphStyleAttributeName - else if ([coreTextKey isEqualToString:(NSString *)kCTParagraphStyleAttributeName]) { + else if ([coreTextKey isEqualToString:(NSString *)kCTParagraphStyleAttributeName] && ![coreTextValue isKindOfClass:[NSParagraphStyle class]]) { cleanAttributes[NSParagraphStyleAttributeName] = [NSParagraphStyle paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreTextValue]; } // kCTStrokeWidthAttributeName -> NSStrokeWidthAttributeName diff --git a/AsyncDisplayKitTests/ASTextKitCoreTextAdditionsTests.m b/AsyncDisplayKitTests/ASTextKitCoreTextAdditionsTests.m index a33c9e2313..6fa7fd7aed 100644 --- a/AsyncDisplayKitTests/ASTextKitCoreTextAdditionsTests.m +++ b/AsyncDisplayKitTests/ASTextKitCoreTextAdditionsTests.m @@ -12,6 +12,11 @@ #import "ASTextKitCoreTextAdditions.h" +BOOL floatsCloseEnough(CGFloat float1, CGFloat float2) { + CGFloat epsilon = 0.00001; + return (fabs(float1 - float2) < epsilon); +} + @interface ASTextKitCoreTextAdditionsTests : XCTestCase @end @@ -44,5 +49,21 @@ XCTAssertTrue([testString isEqualToAttributedString:actualCleansedString], @"Expected the output string %@ to be the same as the input %@ if there are no core text attributes", actualCleansedString, testString); } +- (void)testNSParagraphStyleNoCleansing +{ + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.lineSpacing = 10.0; + + //NSUnderlineStyleAttributeName flags the unsupported CT attribute check + NSDictionary *attributes = @{NSParagraphStyleAttributeName:paragraphStyle, + NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)}; + + NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:@"Test" attributes:attributes]; + NSAttributedString *cleansedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); + + NSParagraphStyle *cleansedParagraphStyle = [cleansedString attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL]; + + XCTAssertTrue(floatsCloseEnough(cleansedParagraphStyle.lineSpacing, paragraphStyle.lineSpacing), @"Expected the output line spacing: %f to be equal to the input line spacing: %f", cleansedParagraphStyle.lineSpacing, paragraphStyle.lineSpacing); +} @end From 4ceab33038f4b9bc70303f38c9c9bb52f3b85618 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Wed, 16 Dec 2015 10:20:13 +0000 Subject: [PATCH 06/16] Further clean up for ASDK 2.0 --- AsyncDisplayKit/ASMapNode.h | 5 +- AsyncDisplayKit/ASMapNode.mm | 95 ++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index d47a1343eb..acabf84152 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -11,7 +11,10 @@ @interface ASMapNode : ASImageNode -- (instancetype)initWithRegion:(MKCoordinateRegion)region NS_DESIGNATED_INITIALIZER; +/** + The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. + */ +@property (nonatomic, assign) MKCoordinateRegion region; /** 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. diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index bf5e3570ae..80a76fc82d 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -17,19 +17,18 @@ MKMapSnapshotter *_snapshotter; MKMapSnapshotOptions *_options; NSArray *_annotations; - ASDisplayNode *_mapNode; CLLocationCoordinate2D _centerCoordinateOfMap; } @end @implementation ASMapNode -@synthesize liveMap = _liveMap; @synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange; @synthesize mapDelegate = _mapDelegate; +@synthesize region = _region; #pragma mark - Lifecycle -- (instancetype)initWithRegion:(MKCoordinateRegion)region +- (instancetype)init { if (!(self = [super init])) { return nil; @@ -38,11 +37,12 @@ self.clipsToBounds = YES; _needsMapReloadOnBoundsChange = YES; - _liveMap = NO; + _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; + _region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(43.432858, 13.183671), MKCoordinateSpanMake(0.2, 0.2)); _options = [[MKMapSnapshotOptions alloc] init]; - _options.region = region; + _options.region = _region; return self; } @@ -50,7 +50,7 @@ - (void)didLoad { [super didLoad]; - if (self.isLiveMap && !_mapNode) { + if ([self wasLiveMapPreviously]) { self.userInteractionEnabled = YES; [self addLiveMap]; } @@ -59,7 +59,7 @@ - (void)fetchData { [super fetchData]; - if (_liveMap && !_mapNode) { + if ([self wasLiveMapPreviously]) { [self addLiveMap]; } else { [self setUpSnapshotter]; @@ -70,27 +70,27 @@ - (void)clearFetchedData { [super clearFetchedData]; - [self removeLiveMap]; + if (self.isLiveMap) { + [self removeLiveMap]; + } } #pragma mark - Settings - (BOOL)isLiveMap { - ASDN::MutexLocker l(_propertyLock); - return _liveMap; + return (_mapView != nil); } - (void)setLiveMap:(BOOL)liveMap { - ASDN::MutexLocker l(_propertyLock); - if (liveMap == _liveMap) { - return; - } - _liveMap = liveMap; liveMap ? [self addLiveMap] : [self removeLiveMap]; } +- (BOOL)wasLiveMapPreviously +{ + return CLLocationCoordinate2DIsValid(_centerCoordinateOfMap); +} - (BOOL)needsMapReloadOnBoundsChange { @@ -104,6 +104,24 @@ _needsMapReloadOnBoundsChange = needsMapReloadOnBoundsChange; } +- (MKCoordinateRegion)region +{ + ASDN::MutexLocker l(_propertyLock); + return _region; +} + +- (void)setRegion:(MKCoordinateRegion)region +{ + ASDN::MutexLocker l(_propertyLock); + _region = region; + if (self.isLiveMap) { + [_mapView setRegion:_region animated:YES]; + } else { + _options.region = _region; + [self resetSnapshotter]; + [self takeSnapshot]; + } +} #pragma mark - Snapshotter @@ -164,55 +182,49 @@ #pragma mark - Actions - (void)addLiveMap { - if (self.isNodeLoaded && !_mapNode) { + ASDisplayNodeAssertMainThread(); + if (!self.isLiveMap) { __weak ASMapNode *weakSelf = self; - _mapNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ - _mapView = [[MKMapView alloc] initWithFrame:CGRectZero]; - _mapView.delegate = _mapDelegate; - [_mapView setRegion:_options.region]; - [_mapView addAnnotations:_annotations]; - [weakSelf setNeedsLayout]; - return _mapView; - }]; - [self addSubnode:_mapNode]; + _mapView = [[MKMapView alloc] initWithFrame:CGRectZero]; + _mapView.delegate = weakSelf.mapDelegate; + [_mapView setRegion:_options.region]; + [_mapView addAnnotations:_annotations]; + [weakSelf setNeedsLayout]; + [weakSelf.view addSubview:_mapView]; if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) { [_mapView setCenterCoordinate:_centerCoordinateOfMap]; + } else { + _centerCoordinateOfMap = _options.region.center; } } } - (void)removeLiveMap { - if (_mapNode) { - _centerCoordinateOfMap = _mapView.centerCoordinate; - [_mapNode removeFromSupernode]; - _mapView = nil; - _mapNode = nil; - } + _centerCoordinateOfMap = _mapView.centerCoordinate; + [_mapView removeFromSuperview]; + _mapView = nil; } - (void)setAnnotations:(NSArray *)annotations { ASDN::MutexLocker l(_propertyLock); _annotations = [annotations copy]; - if (annotations.count != _annotations.count) { - // Redraw - [self setNeedsDisplay]; - if (_mapView) { - [_mapView removeAnnotations:_mapView.annotations]; - [_mapView addAnnotations:annotations]; - } + if (self.isLiveMap) { + [_mapView removeAnnotations:_mapView.annotations]; + [_mapView addAnnotations:annotations]; + } else { + [self takeSnapshot]; } } - #pragma mark - Layout // 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) { + if (self.isLiveMap) { _mapView.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, self.calculatedSize.height); } else { // If our bounds.size is different from our current snapshot size, then let's request a new image from MKMapSnapshotter. @@ -223,5 +235,4 @@ } } } - -@end +@end \ No newline at end of file From 71c44843c8881d84519890c888af07cd097d6c59 Mon Sep 17 00:00:00 2001 From: rcancro <@pinterest.com> Date: Wed, 16 Dec 2015 13:14:33 -0800 Subject: [PATCH 07/16] enforce pixels bounds for ASLayout size/position --- AsyncDisplayKit/Layout/ASLayout.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/Layout/ASLayout.mm b/AsyncDisplayKit/Layout/ASLayout.mm index 92e2d307ec..745b325e52 100644 --- a/AsyncDisplayKit/Layout/ASLayout.mm +++ b/AsyncDisplayKit/Layout/ASLayout.mm @@ -11,6 +11,7 @@ #import "ASLayout.h" #import "ASAssert.h" #import "ASLayoutSpecUtilities.h" +#import "ASInternalHelpers.h" #import CGPoint const CGPointNull = {NAN, NAN}; @@ -37,8 +38,12 @@ extern BOOL CGPointIsNull(CGPoint point) ASLayout *l = [super new]; if (l) { l->_layoutableObject = layoutableObject; - l->_size = size; - l->_position = position; + l->_size = CGSizeMake(ASCeilPixelValue(size.width), ASCeilPixelValue(size.height)); + if (CGPointIsNull(position) == NO) { + l->_position = CGPointMake(ASCeilPixelValue(position.x), ASCeilPixelValue(position.y)); + } else { + l->_position = position; + } l->_sublayouts = [sublayouts copy]; } return l; From 2e6e81e66b2ccebd0ae19ac3140830beaa2d37aa Mon Sep 17 00:00:00 2001 From: rcancro <@pinterest.com> Date: Wed, 16 Dec 2015 15:34:30 -0800 Subject: [PATCH 08/16] Don't allow unitialized or under constrained layouts cause a crash. Should I move the pixel bounds rounding to here instead of leaving it in ASLayout? --- AsyncDisplayKit/ASDisplayNode.mm | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 0ca022172e..7758561d96 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1816,8 +1816,28 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer) CGRect subnodeFrame = CGRectZero; for (ASLayout *subnodeLayout in _layout.sublayouts) { ASDisplayNodeAssert([_subnodes containsObject:subnodeLayout.layoutableObject], @"Cached sublayouts must only contain subnodes' layout."); - subnodeFrame.origin = subnodeLayout.position; - subnodeFrame.size = subnodeLayout.size; + CGPoint adjustedOrigin = subnodeLayout.position; + if (isfinite(adjustedOrigin.x) == NO) { + ASDisplayNodeAssert(0, @"subnodeLayout has an invalid position"); + adjustedOrigin.x = 0; + } + if (isfinite(adjustedOrigin.y) == NO) { + ASDisplayNodeAssert(0, @"subnodeLayout has an invalid position"); + adjustedOrigin.y = 0; + } + subnodeFrame.origin = adjustedOrigin; + + CGSize adjustedSize = subnodeLayout.size; + if (isfinite(adjustedSize.width) == NO) { + ASDisplayNodeAssert(0, @"subnodeLayout has an invalid size"); + adjustedSize.width = 0; + } + if (isfinite(adjustedSize.height) == NO) { + ASDisplayNodeAssert(0, @"subnodeLayout has an invalid position"); + adjustedSize.height = 0; + } + subnodeFrame.size = adjustedSize; + subnode = ((ASDisplayNode *)subnodeLayout.layoutableObject); [subnode setFrame:subnodeFrame]; } From f44c82956440bceb62d99e92085b2efb41193555 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Wed, 16 Dec 2015 17:20:08 -0800 Subject: [PATCH 09/16] ASTextNode shouldn't create a long press gesture recognizer unless the delegate cares about the callback. --- AsyncDisplayKit/ASTextNode.h | 5 +++++ AsyncDisplayKit/ASTextNode.mm | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASTextNode.h b/AsyncDisplayKit/ASTextNode.h index db66b09e13..1a47f3d730 100644 --- a/AsyncDisplayKit/ASTextNode.h +++ b/AsyncDisplayKit/ASTextNode.h @@ -194,6 +194,9 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) { /** @abstract Responds to actions from links in the text node. + @discussion The delegate must be set before the node is loaded, and implement + textNode:longPressedLinkAttribute:value:atPoint:textRange: in order for + the long press gesture recognizer to be installed. */ @property (nonatomic, weak) id delegate; @@ -233,6 +236,8 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) { @param value The value of the tapped attribute. @param point The point within textNode, in textNode's coordinate system, that was tapped. @param textRange The range of highlighted text. + @discussion In addition to implementing this method, the delegate must be set on the text + node before it is loaded (the recognizer is created in -didLoad) */ - (void)textNode:(ASTextNode *)textNode longPressedLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point textRange:(NSRange)textRange; diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 315638093f..e4a0e09e1c 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -211,8 +211,9 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation { [super didLoad]; - // If we are view-backed, support gesture interaction. - if (!self.isLayerBacked) { + // If we are view-backed and the delegate cares, support the long-press callback. + SEL longPressCallback = @selector(textNode:longPressedLinkAttribute:value:atPoint:textRange:); + if (!self.isLayerBacked && [self.delegate respondsToSelector:longPressCallback]) { _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_handleLongPress:)]; _longPressGestureRecognizer.cancelsTouchesInView = self.longPressCancelsTouches; _longPressGestureRecognizer.delegate = self; From aea5a3318e48ef16e0c916567d5bbc4f3be1cbf5 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Mon, 7 Dec 2015 19:12:34 -0800 Subject: [PATCH 10/16] Implement simple horizontal paging node --- AsyncDisplayKit.xcodeproj/project.pbxproj | 12 + AsyncDisplayKit/ASPagerNode.h | 29 ++ AsyncDisplayKit/ASPagerNode.m | 72 ++++ examples/PagerNode/Default-568h@2x.png | Bin 0 -> 17520 bytes examples/PagerNode/Default-667h@2x.png | Bin 0 -> 18314 bytes examples/PagerNode/Default-736h@3x.png | Bin 0 -> 23380 bytes examples/PagerNode/Podfile | 3 + .../Sample.xcodeproj/project.pbxproj | 374 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Sample.xcscheme | 91 +++++ .../contents.xcworkspacedata | 10 + examples/PagerNode/Sample/AppDelegate.h | 18 + examples/PagerNode/Sample/AppDelegate.m | 27 ++ examples/PagerNode/Sample/Info.plist | 36 ++ examples/PagerNode/Sample/PageNode.h | 13 + examples/PagerNode/Sample/PageNode.m | 24 ++ examples/PagerNode/Sample/ViewController.h | 16 + examples/PagerNode/Sample/ViewController.m | 57 +++ examples/PagerNode/Sample/main.m | 20 + 19 files changed, 809 insertions(+) create mode 100644 AsyncDisplayKit/ASPagerNode.h create mode 100644 AsyncDisplayKit/ASPagerNode.m create mode 100644 examples/PagerNode/Default-568h@2x.png create mode 100644 examples/PagerNode/Default-667h@2x.png create mode 100644 examples/PagerNode/Default-736h@3x.png create mode 100644 examples/PagerNode/Podfile create mode 100644 examples/PagerNode/Sample.xcodeproj/project.pbxproj create mode 100644 examples/PagerNode/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 examples/PagerNode/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme create mode 100644 examples/PagerNode/Sample.xcworkspace/contents.xcworkspacedata create mode 100644 examples/PagerNode/Sample/AppDelegate.h create mode 100644 examples/PagerNode/Sample/AppDelegate.m create mode 100644 examples/PagerNode/Sample/Info.plist create mode 100644 examples/PagerNode/Sample/PageNode.h create mode 100644 examples/PagerNode/Sample/PageNode.m create mode 100644 examples/PagerNode/Sample/ViewController.h create mode 100644 examples/PagerNode/Sample/ViewController.m create mode 100644 examples/PagerNode/Sample/main.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 4269a60b2e..702da0f10b 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -190,6 +190,10 @@ 258FF4281C0D152600A83844 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; }; 25A977EF1C0D2A5500406B62 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; }; 25BAA16F1C0D18D2002747C7 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = 258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */; }; + 25E327561C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; }; + 25E327571C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; }; + 25E327581C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; + 25E327591C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; 2767E9411BB19BD600EA9B77 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2767E9421BB19BD600EA9B77 /* ASViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */; }; 2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; }; @@ -644,6 +648,8 @@ 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = ""; }; 258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerVisible.h; sourceTree = ""; }; 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeHandlerVisible.mm; sourceTree = ""; }; + 25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPagerNode.h; sourceTree = ""; }; + 25E327551C16819500A2170C /* ASPagerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPagerNode.m; sourceTree = ""; }; 2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = ""; }; 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = ""; }; 292C599A1A956527007E5DD6 /* ASRangeHandlerPreload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerPreload.h; sourceTree = ""; }; @@ -911,6 +917,8 @@ AC6456051B0A333200CF11B8 /* Layout */, 257754661BED245B00737CA5 /* TextKit */, 058D09B2195D04C000B7D73C /* Supporting Files */, + 25E327541C16819500A2170C /* ASPagerNode.h */, + 25E327551C16819500A2170C /* ASPagerNode.m */, ); path = AsyncDisplayKit; sourceTree = ""; @@ -1246,6 +1254,7 @@ 058D0A83195D060300B7D73C /* ASBaseDefines.h in Headers */, 054963491A1EA066000F8E56 /* ASBasicImageDownloader.h in Headers */, 2967F9E21AB0A5190072E4AB /* ASBasicImageDownloaderInternal.h in Headers */, + 25E327561C16819500A2170C /* ASPagerNode.h in Headers */, 299DA1A91A828D2900162D41 /* ASBatchContext.h in Headers */, 251B8EF91BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h in Headers */, 044285071BAA63FE00D16268 /* ASBatchFetching.h in Headers */, @@ -1438,6 +1447,7 @@ B350622D1B010EFD0018CF92 /* ASScrollDirection.h in Headers */, 254C6B751BF94DF4003EC431 /* ASTextKitHelpers.h in Headers */, B35062081B010EFD0018CF92 /* ASScrollNode.h in Headers */, + 25E327571C16819500A2170C /* ASPagerNode.h in Headers */, B35062551B010EFD0018CF92 /* ASSentinel.h in Headers */, 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */, 9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */, @@ -1687,6 +1697,7 @@ 058D0A28195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm in Sources */, 058D0A29195D050800B7D73C /* ASDisplayNode+DebugTiming.mm in Sources */, 058D0A2A195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm in Sources */, + 25E327581C16819500A2170C /* ASPagerNode.m in Sources */, 058D0A14195D050800B7D73C /* ASDisplayNode.mm in Sources */, 058D0A15195D050800B7D73C /* ASDisplayNodeExtras.mm in Sources */, 0587F9BE1A7309ED00AFF0BA /* ASEditableTextNode.mm in Sources */, @@ -1815,6 +1826,7 @@ B350621A1B010EFD0018CF92 /* ASDealloc2MainObject.m in Sources */, 34EFC75C1B701BD200AD841F /* ASDimension.mm in Sources */, B350624E1B010EFD0018CF92 /* ASDisplayNode+AsyncDisplay.mm in Sources */, + 25E327591C16819500A2170C /* ASPagerNode.m in Sources */, B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */, 254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */, B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */, diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h new file mode 100644 index 0000000000..ec400259cd --- /dev/null +++ b/AsyncDisplayKit/ASPagerNode.h @@ -0,0 +1,29 @@ +// +// ASPagerNode.h +// AsyncDisplayKit +// +// Created by Levi McCallum on 12/7/15. +// Copyright © 2015 Facebook. All rights reserved. +// + +#import + +@protocol ASPagerNodeDataSource; + +@interface ASPagerNode : ASCollectionNode + +@property (weak, nonatomic) id dataSource; + +- (void)reloadData; + +- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType; + +@end + +@protocol ASPagerNodeDataSource + +- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; + +- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index; + +@end \ No newline at end of file diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m new file mode 100644 index 0000000000..2d15c15bc8 --- /dev/null +++ b/AsyncDisplayKit/ASPagerNode.m @@ -0,0 +1,72 @@ +// +// ASPagerNode.m +// AsyncDisplayKit +// +// Created by Levi McCallum on 12/7/15. +// Copyright © 2015 Facebook. All rights reserved. +// + +#import "ASPagerNode.h" + +@interface ASPagerNode () { + UICollectionViewFlowLayout *_flowLayout; +} + +@end + +@implementation ASPagerNode + +- (instancetype)init +{ + _flowLayout = [[UICollectionViewFlowLayout alloc] init]; + _flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + _flowLayout.minimumInteritemSpacing = 0; + _flowLayout.minimumLineSpacing = 0; + + self = [super initWithCollectionViewLayout:_flowLayout]; + if (self != nil) { + self.view.asyncDataSource = self; + self.view.asyncDelegate = self; + + self.view.pagingEnabled = YES; + self.view.allowsSelection = NO; + self.view.showsVerticalScrollIndicator = NO; + self.view.showsHorizontalScrollIndicator = NO; + + ASRangeTuningParameters tuningParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 }; + [self setTuningParameters:tuningParams forRangeType:ASLayoutRangeTypePreload]; + [self setTuningParameters:tuningParams forRangeType:ASLayoutRangeTypeRender]; + } + return self; +} + +- (void)reloadData +{ + [self.view reloadData]; +} + +- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType +{ + [self.view setTuningParameters:tuningParameters forRangeType:rangeType]; +} + +#pragma mark - ASCollectionViewDataSource + +- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes"); + return [self.dataSource pagerNode:self nodeAtIndex:indexPath.item]; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes"); + return [self.dataSource numberOfPagesInPagerNode:self]; +} + +- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath +{ + return ASSizeRangeMake(CGSizeZero, self.view.bounds.size); +} + +@end diff --git a/examples/PagerNode/Default-568h@2x.png b/examples/PagerNode/Default-568h@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ee80b93937cd9dd79502629b14fe09aa03cacc2 GIT binary patch literal 17520 zcmeI3&2QsG7{;dyhuxq(aR70$vO)rco)4~Hqb-mA2=CIb8^QK*gwP8wCVy+_i!WbB=&euO z!=w19^{!?6gA#W9HYtq<0qu=Ybz>Z0`-H?on{-{TR{Zmu?}~!!)QWeFmfQ*&q~~s* zhveXV_s~8+u`5n-qh6?vEov|zF&4&yz86{JS~2yt=yB346@|1*d{QfJCIbpbtv#XP zheR++hG@%*E|`^)Vkml9c~ekjMU!MrQZ!LfExBSThA{aQ>jipL4V{j)-@H8;jz+a& zFOCCCl18IZX{43>uq!E*N=1@YNmWJKLyXS67>`9Sx|NwseVQb)LpO+B-xCsF-1diY ztyoM3ntdkMH3(({dC`O&r6`SYASoqTS|)PrnI;&9{q)ovTOxfjAYL3%ow8IH^!(V5 zdj5(bXX%v#(>ZCiW@9fs-@#z%&{4c~N)b$uE>%W{X91D+N#qYhn{1uZOS!e|>SMPv zpPUO$NoM7_ld-!(mSi$nx)ib*s?uw<8X>{4A0GOCzn-nKy(vPW(GXs1VcYc*q_0;c z*nd9Rb1TxsF{#tVsEdj$D*B-+TUy1EO;I*2Sj^#R z=5cV0FXfW&oAYsOtK)|Q9M|0e?h+~Rx>af3nCm%PQdYz7`yo9oQrD`|vgVvBU1rvf z7sc4K$xgFQ8%nP0Sc)olh@)wuzTR$&x`VM;Hf>YXY_n{bs#dn!Y6`K{%F7q5o4!3v zw#vlXq1KM0n~q5oQE_zYZ)g>1Jsbid6i*sMS$nsnP**iK4W z-A;A`ajMdV*7<48loOe|IDwa=ocZVEtH&7ih{xJcnN`|rwMpc6;t>wXW|yvs$8Pk@ z@}dTMSEZ!x_uck_9fO)qQO@GMQ+b+k+QN;k1G;mdod%W(l9?2zMP^8s0o3jkq<92c7p$Z}i&2s`As z*nB{i;{rg~A;-n$1F{?!0KyJAE;b*K<+uP4cF1wD`G73P1%R+aj*HC)WH~MXgdK8R zY(5~%aRDIgkmF+W0a=a<0AYt57n={ra$EoiJ7nT2%-^yl9(}cTMBkzP^v2h3(D!cz zdwaiy(D|zfJ@^QrzyG1%zali05&G>uLe}R9z2tv(@5kE+U4MV4xp_GL`Sg5w7{{k8fuN`-gg~6EtdKy$@q3ealPsm_(n_S1wutt$JFzFN)xMF-1^Yl zKS&PRZ`w}KFH<+@u=1!M^4^5hZ;wLioUladup`fJl>Yeo+mhtDjncbTTWyEy?AY5p zkJ#S%_P%p|;?&&I?dEcQWOIW)OQbw>80kV~ynhxlWtYXlAadBoDZiAPi>^NL zy0gi-;FM-AJ$E+pE|H~~T$U|`e1_`$TJ80S(IklWgP_;USJ}=4p|rj(z1*gb=chz*y}FfH5CiynoZ z(1ULtmnQT|F2%kDAJ?(FLDZ*7)9ceCriA`cU70l&dQO*=y&m*}h@Tc~8g*q+b3v6Y zGkeRA6Y4u`tJUNUWzTbMv)ZYeIx}Tvs=93I-HKc_OiS*t8m(1Toz=z=+wG!!&bk#i zgLJEmtzB+S4XSl5!;n{9oyw*`b-6>UrmUK^il*vDw??bk{BY}ne9ro<$m3;>_6mK{ zv;U_`>IE_XGxBbybA%AHk*$y&Essi=Cl+F`4c zIsUhEU>dfjO$yTgGzYWw>l{=6h`CK=a#@px$7$NGR{I`p>s+{xJnqw$@4<_ua8kkN zOJ_ZOc(8fd2=@U+V2j1fk5@J z8HQPu7E)trK3jz+=d5(*t^B#1|0GbRzX|55>h#WYod>gPx=vT%g@XVf;t+9(`G73q z0zkwe;u7-#S;Pf^h(p9B<^!^b3jh&^h)c`|WDyqtA`TIkm=DMzE&xOvA}%o>kVRYo zh&V)CVm=^?xBw7wh`7XjKo)TUAmR{liTQvm;sQX#A>tDA0a?TafQUoHCFTRNhzkG_ zhloqe2V@Z!03r?%mzWR8A}#<#93n0;ACN^{0Ejq5Tw*>Ti?{#~afrCYd_Wd)0U+WK zaf$hWEaCz{#3AAm^8s1J1%QY{#3kkfvWN=+5r;xt%d@v^na^LX9rAZ*rRRS9n7@B3 zIh(s}Le5_zCFIw8gxH@D@_g{o-5>7o_jw0ft+oBp&%b@Yw8WM7 zrH5boo3EvZ_(1|l00|%gB!C2v01`j~NZ=X>eD`35{4^j-PY%DimD+7>Y`4C6{oeh* E06EB-U;qFB literal 0 HcmV?d00001 diff --git a/examples/PagerNode/Default-736h@3x.png b/examples/PagerNode/Default-736h@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8949cae16a4217842bd8ad813422c6b02e7cafa GIT binary patch literal 23380 zcmeI3&2QsG7{;dvp`~agBn}`rU}c2_5{^Co*u*CBswBI#5^1Zpi0)~3Y)@Ki6WiGC zChY|TCvFHXE5u>%NL;wV0fEGo^J@PC5E5KCaDuU&4|kFdg zdhMfNZ$I1by=i;VuulBQrS}<*{ybMEgw+Y z?`=z+D4~*BH)T)7hSad?*u+K?zba`e))iG(ur6cGRxKNw(&STfR@qT2@%#2p_u6DQ z7PV`KSr*%hG8&EQBfTCa2MV?4Y7lsEkRh;JT_T6Zzgu6CWjm;?#Ukp#wUkVU{u-UaE@^ zqby1fqcet_rOzCg%}K8}8++;b4u?yJPP41G8G;GYrOI^gIHt-DO{1g4qgQXUOS!b{ z>a(CfpPW-pdFIS>r{mxZS)M6n#Zo9|sKu_;?j)3CQL-0B1E*YN+f#&6rz5@GBVG{Z zNMC6weE<1m&#h>eWYl4c(U7q!V`EQKZH#RestsFJD<)-6&Z8IkLH~G(hhf@Aqv}!V z$$PNP%ca`4;^TXEKT3uqbAll`ph_Gbw3K;crRQu(*_~(*CG51Qqqmf0%@tL# z%OtV!#5ekuMW}3fo+cYjqbZZ7=E~GCvFmv%we)@gvDd507p%LH zca(3HiM7wHU9)NG4c*OMb=lB-OLlervW%Ms#tqVRUEP{mSL6%UTS>sm92r#lFw}aGvc-8^S+s2F7KLn=zH_>DnivE{L5fL|(tNwMYt#KUt6;MNm1~M^YZEUo zWsaBc2I{wzQ?2vUnkgr;U~vM^N4fN`$j=^QbVx(dhAOR!UT2%6Q9m1zgsvU1HSw1l zy|g^7;k{c*UiSyVzc33ax&2^sKn+c6P*;_G^K!n@JzsX48kQ}r_EkzOqv5;LIsT_} zU}&~ED@gy*9L(3RcSynm>O0ExvZf7>(zKng_C46vIdva-)Tgc7gQrX3w1O{|&Q|{L zV6(EzN&qR!9d0QLZSw_F_TSIT=isR5-_TU{QE>i$BCV!*>25)XkQ{H}i_^U`z-5-GJRH)BFa2HG_>+sQA=U>Gio()6`~F zT1ic$<#bgZor~I8wz3Cv_M1SN{U}%{tFv3r!#tQ@)5CP-ykHOxh&TjXVm@3JaB)Dy zA>b18;j(~>10oIqmzWQi1za2uaR|7?e7G#&;(&-lz$NCxWdRolL>vMxF&{1qxHur< z5O9h4a9O~`0TG9QOU#GM0xk}SI0Rf`K3o=XaX`c&;1cuUvVe;NA`StUm=Bi)TpSQ_ z2)M+2xGdn}fQUoDCFa9r0T%~E90D#eA1({HI3VH>aEbYFS-`~s5r=?F%!kVYE)Iw| z1YBZ1To!O~K*S;767%7*fQthn4gr^#50?d891w9R#I-tq&6bAj-P#d*iT2)B=M(k< zuH>!n^bk6E38D8sKf00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!VbfB+Bx0zd!= l00AHX1c1Q*gn;t`y7MJkdHVCOto({Mu5Na}c>U)4e*&NtopJyG literal 0 HcmV?d00001 diff --git a/examples/PagerNode/Podfile b/examples/PagerNode/Podfile new file mode 100644 index 0000000000..6c012e3c04 --- /dev/null +++ b/examples/PagerNode/Podfile @@ -0,0 +1,3 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' +pod 'AsyncDisplayKit', :path => '../..' diff --git a/examples/PagerNode/Sample.xcodeproj/project.pbxproj b/examples/PagerNode/Sample.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..341304bc51 --- /dev/null +++ b/examples/PagerNode/Sample.xcodeproj/project.pbxproj @@ -0,0 +1,374 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */; }; + 05E2128719D4DB510098F589 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128619D4DB510098F589 /* main.m */; }; + 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128919D4DB510098F589 /* AppDelegate.m */; }; + 05E2128D19D4DB510098F589 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128C19D4DB510098F589 /* ViewController.m */; }; + 252041E21C167DFC00E264C8 /* PageNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 252041E11C167DFC00E264C8 /* PageNode.m */; }; + 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */; }; + 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AA19EE274300767484 /* Default-667h@2x.png */; }; + 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AB19EE274300767484 /* Default-736h@3x.png */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = ""; }; + 05E2128119D4DB510098F589 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 05E2128519D4DB510098F589 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 05E2128619D4DB510098F589 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 05E2128819D4DB510098F589 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 05E2128919D4DB510098F589 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 05E2128B19D4DB510098F589 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 05E2128C19D4DB510098F589 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + 252041E01C167DFC00E264C8 /* PageNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageNode.h; sourceTree = ""; }; + 252041E11C167DFC00E264C8 /* PageNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageNode.m; sourceTree = ""; }; + 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 6C2C82AA19EE274300767484 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; }; + 6C2C82AB19EE274300767484 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; }; + C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 05E2127E19D4DB510098F589 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 05E2127819D4DB510098F589 = { + isa = PBXGroup; + children = ( + 05E2128319D4DB510098F589 /* Sample */, + 05E2128219D4DB510098F589 /* Products */, + 1A943BF0259746F18D6E423F /* Frameworks */, + 1AE410B73DA5C3BD087ACDD7 /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 05E2128219D4DB510098F589 /* Products */ = { + isa = PBXGroup; + children = ( + 05E2128119D4DB510098F589 /* Sample.app */, + ); + name = Products; + sourceTree = ""; + }; + 05E2128319D4DB510098F589 /* Sample */ = { + isa = PBXGroup; + children = ( + 252041E01C167DFC00E264C8 /* PageNode.h */, + 252041E11C167DFC00E264C8 /* PageNode.m */, + 05E2128819D4DB510098F589 /* AppDelegate.h */, + 05E2128919D4DB510098F589 /* AppDelegate.m */, + 05E2128B19D4DB510098F589 /* ViewController.h */, + 05E2128C19D4DB510098F589 /* ViewController.m */, + 05E2128419D4DB510098F589 /* Supporting Files */, + ); + path = Sample; + sourceTree = ""; + }; + 05E2128419D4DB510098F589 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */, + 6C2C82AA19EE274300767484 /* Default-667h@2x.png */, + 6C2C82AB19EE274300767484 /* Default-736h@3x.png */, + 05E2128519D4DB510098F589 /* Info.plist */, + 05E2128619D4DB510098F589 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 1A943BF0259746F18D6E423F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1AE410B73DA5C3BD087ACDD7 /* Pods */ = { + isa = PBXGroup; + children = ( + C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */, + 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 05E2128019D4DB510098F589 /* Sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */; + buildPhases = ( + E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */, + 05E2127D19D4DB510098F589 /* Sources */, + 05E2127E19D4DB510098F589 /* Frameworks */, + 05E2127F19D4DB510098F589 /* Resources */, + F012A6F39E0149F18F564F50 /* Copy Pods Resources */, + D668455448B2FFAC9BEF28DD /* Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Sample; + productName = Sample; + productReference = 05E2128119D4DB510098F589 /* Sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 05E2127919D4DB510098F589 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0710; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 05E2128019D4DB510098F589 = { + CreatedOnToolsVersion = 6.0.1; + }; + }; + }; + buildConfigurationList = 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 05E2127819D4DB510098F589; + productRefGroup = 05E2128219D4DB510098F589 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 05E2128019D4DB510098F589 /* Sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 05E2127F19D4DB510098F589 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */, + 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */, + 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + D668455448B2FFAC9BEF28DD /* 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; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + F012A6F39E0149F18F564F50 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 05E2127D19D4DB510098F589 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 05E2128D19D4DB510098F589 /* ViewController.m in Sources */, + 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */, + 05E2128719D4DB510098F589 /* main.m in Sources */, + 252041E21C167DFC00E264C8 /* PageNode.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 05E212A219D4DB510098F589 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 05E212A319D4DB510098F589 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 05E212A519D4DB510098F589 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Sample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 05E212A619D4DB510098F589 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Sample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 05E212A219D4DB510098F589 /* Debug */, + 05E212A319D4DB510098F589 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 05E212A519D4DB510098F589 /* Debug */, + 05E212A619D4DB510098F589 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 05E2127919D4DB510098F589 /* Project object */; +} diff --git a/examples/PagerNode/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/PagerNode/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..a80c038249 --- /dev/null +++ b/examples/PagerNode/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/PagerNode/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/PagerNode/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme new file mode 100644 index 0000000000..0b71c455d1 --- /dev/null +++ b/examples/PagerNode/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/PagerNode/Sample.xcworkspace/contents.xcworkspacedata b/examples/PagerNode/Sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7b5a2f3050 --- /dev/null +++ b/examples/PagerNode/Sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/examples/PagerNode/Sample/AppDelegate.h b/examples/PagerNode/Sample/AppDelegate.h new file mode 100644 index 0000000000..2aa29369b4 --- /dev/null +++ b/examples/PagerNode/Sample/AppDelegate.h @@ -0,0 +1,18 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/examples/PagerNode/Sample/AppDelegate.m b/examples/PagerNode/Sample/AppDelegate.m new file mode 100644 index 0000000000..1dea563b77 --- /dev/null +++ b/examples/PagerNode/Sample/AppDelegate.m @@ -0,0 +1,27 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "AppDelegate.h" + +#import "ViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.backgroundColor = [UIColor whiteColor]; + self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]]; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/examples/PagerNode/Sample/Info.plist b/examples/PagerNode/Sample/Info.plist new file mode 100644 index 0000000000..fb4115c84c --- /dev/null +++ b/examples/PagerNode/Sample/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/PagerNode/Sample/PageNode.h b/examples/PagerNode/Sample/PageNode.h new file mode 100644 index 0000000000..b8843378de --- /dev/null +++ b/examples/PagerNode/Sample/PageNode.h @@ -0,0 +1,13 @@ +// +// PageNode.h +// Sample +// +// Created by McCallum, Levi on 12/7/15. +// Copyright © 2015 Facebook. All rights reserved. +// + +#import + +@interface PageNode : ASCellNode + +@end diff --git a/examples/PagerNode/Sample/PageNode.m b/examples/PagerNode/Sample/PageNode.m new file mode 100644 index 0000000000..2a60c8982b --- /dev/null +++ b/examples/PagerNode/Sample/PageNode.m @@ -0,0 +1,24 @@ +// +// PageNode.m +// Sample +// +// Created by McCallum, Levi on 12/7/15. +// Copyright © 2015 Facebook. All rights reserved. +// + +#import "PageNode.h" + +@implementation PageNode + +- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize +{ + return [ASLayout layoutWithLayoutableObject:self size:constrainedSize.max]; +} + +- (void)fetchData +{ + [super fetchData]; + NSLog(@"Fetching data for node: %@", self); +} + +@end diff --git a/examples/PagerNode/Sample/ViewController.h b/examples/PagerNode/Sample/ViewController.h new file mode 100644 index 0000000000..d4ec993c7b --- /dev/null +++ b/examples/PagerNode/Sample/ViewController.h @@ -0,0 +1,16 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface ViewController : ASViewController + +@end diff --git a/examples/PagerNode/Sample/ViewController.m b/examples/PagerNode/Sample/ViewController.m new file mode 100644 index 0000000000..e10d013ec8 --- /dev/null +++ b/examples/PagerNode/Sample/ViewController.m @@ -0,0 +1,57 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "ViewController.h" + +#import + +#import "PageNode.h" + +@interface ViewController () + +- (ASPagerNode *)node; + +@end + +@implementation ViewController + +- (instancetype)init +{ + if (!(self = [super initWithNode:[[ASPagerNode alloc] init]])) + return nil; + + [self node].dataSource = self; + + self.title = @"Pages"; + + return self; +} + +- (ASPagerNode *)node +{ + return (ASPagerNode *)[super node]; +} + +#pragma mark - ASPagerNodeDataSource + +- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode +{ + return 5; +} + +- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index +{ + PageNode *page = [[PageNode alloc] init]; + page.backgroundColor = [UIColor blueColor]; + return page; +} + +@end diff --git a/examples/PagerNode/Sample/main.m b/examples/PagerNode/Sample/main.m new file mode 100644 index 0000000000..ae9488711c --- /dev/null +++ b/examples/PagerNode/Sample/main.m @@ -0,0 +1,20 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} From 473085db47bd71006f1135d726b15db266f6f301 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Fri, 11 Dec 2015 13:42:25 -0800 Subject: [PATCH 11/16] Move position of ASPagerNodeDataSource to support Travis builds --- AsyncDisplayKit/ASPagerNode.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index ec400259cd..8eb1ab6d1a 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -8,7 +8,15 @@ #import -@protocol ASPagerNodeDataSource; +@class ASPagerNode; + +@protocol ASPagerNodeDataSource + +- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; + +- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index; + +@end @interface ASPagerNode : ASCollectionNode @@ -18,12 +26,4 @@ - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType; -@end - -@protocol ASPagerNodeDataSource - -- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; - -- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index; - @end \ No newline at end of file From 1b5ac3615eb63d2382b7f11bf0baa3f950a0d563 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Fri, 11 Dec 2015 14:44:23 -0800 Subject: [PATCH 12/16] Add ASPagerNode to framework header --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 ++++---- AsyncDisplayKit/ASPagerNode.h | 18 +++++++++--------- AsyncDisplayKit/AsyncDisplayKit.h | 2 ++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 702da0f10b..bc4a7c1c48 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -190,8 +190,8 @@ 258FF4281C0D152600A83844 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; }; 25A977EF1C0D2A5500406B62 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; }; 25BAA16F1C0D18D2002747C7 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = 258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */; }; - 25E327561C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; }; - 25E327571C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; }; + 25E327561C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25E327571C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25E327581C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; 25E327591C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; 2767E9411BB19BD600EA9B77 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -899,6 +899,8 @@ 0516FA3F1A1563D200B4EBED /* ASMultiplexImageNode.mm */, 055B9FA61A1C154B00035D6D /* ASNetworkImageNode.h */, 055B9FA71A1C154B00035D6D /* ASNetworkImageNode.mm */, + 25E327541C16819500A2170C /* ASPagerNode.h */, + 25E327551C16819500A2170C /* ASPagerNode.m */, D785F6601A74327E00291744 /* ASScrollNode.h */, D785F6611A74327E00291744 /* ASScrollNode.m */, B0F880581BEAEC7500D17647 /* ASTableNode.h */, @@ -917,8 +919,6 @@ AC6456051B0A333200CF11B8 /* Layout */, 257754661BED245B00737CA5 /* TextKit */, 058D09B2195D04C000B7D73C /* Supporting Files */, - 25E327541C16819500A2170C /* ASPagerNode.h */, - 25E327551C16819500A2170C /* ASPagerNode.m */, ); path = AsyncDisplayKit; sourceTree = ""; diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index 8eb1ab6d1a..ec400259cd 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -8,15 +8,7 @@ #import -@class ASPagerNode; - -@protocol ASPagerNodeDataSource - -- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; - -- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index; - -@end +@protocol ASPagerNodeDataSource; @interface ASPagerNode : ASCollectionNode @@ -26,4 +18,12 @@ - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType; +@end + +@protocol ASPagerNodeDataSource + +- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; + +- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index; + @end \ No newline at end of file diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 7040834238..0cb9a32f56 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -30,6 +30,8 @@ #import +#import + #import #import From 669fd38dd4acf528be0f6aef3f5fbf22276d92e6 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Fri, 11 Dec 2015 16:02:39 -0800 Subject: [PATCH 13/16] Fix project includes for ASPagerNode --- AsyncDisplayKit/ASCollectionNode.h | 2 +- AsyncDisplayKit/ASCollectionNode.m | 1 + AsyncDisplayKit/ASPagerNode.h | 2 +- AsyncDisplayKit/ASPagerNode.m | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index c0489b2297..d25a6de14e 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -6,7 +6,7 @@ // Copyright (c) 2015 Facebook. All rights reserved. // -#import +#import /** * ASCollectionNode is a node based class that wraps an ASCollectionView. It can be used diff --git a/AsyncDisplayKit/ASCollectionNode.m b/AsyncDisplayKit/ASCollectionNode.m index 0b77d09ff1..680b85a80a 100644 --- a/AsyncDisplayKit/ASCollectionNode.m +++ b/AsyncDisplayKit/ASCollectionNode.m @@ -7,6 +7,7 @@ // #import "ASCollectionNode.h" +#import "ASDisplayNode+Subclasses.h" @implementation ASCollectionNode diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index ec400259cd..89c03fb965 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -6,7 +6,7 @@ // Copyright © 2015 Facebook. All rights reserved. // -#import +#import @protocol ASPagerNodeDataSource; diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m index 2d15c15bc8..8d68b0c192 100644 --- a/AsyncDisplayKit/ASPagerNode.m +++ b/AsyncDisplayKit/ASPagerNode.m @@ -8,6 +8,8 @@ #import "ASPagerNode.h" +#import + @interface ASPagerNode () { UICollectionViewFlowLayout *_flowLayout; } From c6f4aff4ef183046472497d59f0f8a79f95942e9 Mon Sep 17 00:00:00 2001 From: rcancro <@pinterest.com> Date: Thu, 17 Dec 2015 15:20:40 -0800 Subject: [PATCH 14/16] Do not round when resolving relative dimensions When laying out a node I got to a point where the constrained width was min 132.22222pts and max width was 100%. When resolving the relative size to pts it rounded to 132pt. This caused an assert in ASSizeRangeMake because the min width (132.222pt) was bigger than the max width (132pt) --- AsyncDisplayKit/Layout/ASDimension.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Layout/ASDimension.mm b/AsyncDisplayKit/Layout/ASDimension.mm index a0737f6682..a1e42c4b76 100644 --- a/AsyncDisplayKit/Layout/ASDimension.mm +++ b/AsyncDisplayKit/Layout/ASDimension.mm @@ -57,7 +57,7 @@ CGFloat ASRelativeDimensionResolve(ASRelativeDimension dimension, CGFloat parent case ASRelativeDimensionTypePoints: return dimension.value; case ASRelativeDimensionTypePercent: - return round(dimension.value * parent); + return dimension.value * parent; } } From 1872ac07aa7f4c03678d6b00aa6f183514599acd Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Thu, 17 Dec 2015 22:12:29 -0800 Subject: [PATCH 15/16] [ASTextNode] Renderer should not be invalidated if bounds size matches calculatedSize, even if it doesn't match constrainedSize. --- AsyncDisplayKit/ASTextNode.mm | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 4b114b7340..56490d18ba 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -23,6 +23,7 @@ #import "ASInternalHelpers.h" #import "ASEqualityHelpers.h" +#import "ASLayout.h" static const NSTimeInterval ASTextNodeHighlightFadeOutDuration = 0.15; static const NSTimeInterval ASTextNodeHighlightFadeInDuration = 0.1; @@ -290,7 +291,29 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation - (BOOL)_needInvalidateRenderer:(CGSize)newSize { - return !CGSizeEqualToSize(newSize, _constrainedSize); + if (!_renderer) { + return YES; + } + + // If the size is not the same as the constraint we provided to the renderer, start out assuming we need + // a new one. However, there are common cases where the constrained size doesn't need to be the same as calculated. + CGSize oldSize = _renderer.constrainedSize; + + if (CGSizeEqualToSize(newSize, oldSize)) { + return NO; + } else { + // It is very common to have a constrainedSize with a concrete, specific width but +Inf height. + // In this case, as long as the text node has bounds as large as the full calculatedLayout suggests, + // it means that the text has all the room it needs (as it was not vertically bounded). So, we will not + // experience truncation and don't need to recreate the renderer with the size it already calculated, + // as this would essentially serve to set its constrainedSize to be its calculatedSize (unnecessary). + ASLayout *layout = self.calculatedLayout; + if (layout != nil && CGSizeEqualToSize(newSize, layout.size)) { + return NO; + } else { + return YES; + } + } } #pragma mark - Modifying User Text From ee152eadf12efb429f05e425f2c1f4516316a7e9 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Fri, 18 Dec 2015 16:01:19 -0800 Subject: [PATCH 16/16] Remove CALayer and UIView implementations of "name" property. This avoids CoreAnimation from capturing the name from a background thread deep within the internals of AVPlayerLayer, which commits transactions off the main thread. If the main thread is also accessing properties that require the lock, in very specific app architectures relying on AVPlayerLayer, this can cause a deadlock. The "name" property is primarily used by ASDK's unit test infrastructure, so I'm leaving it in place for that purpose - and it may still be used for debugging, if someone wants to set it. It will remain possible to get the node from a layer or view with asyncdisplaykit_node, and access name from there. --- AsyncDisplayKit/ASDisplayNode.h | 2 -- AsyncDisplayKit/ASDisplayNode.mm | 10 ---------- AsyncDisplayKitTests/ASDisplayNodeTests.m | 4 ++-- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 23eb84a6b5..b3c333a5fc 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -685,7 +685,6 @@ typedef NS_OPTIONS(NSUInteger, ASInterfaceState) * @param node The node to be added. */ - (void)addSubnode:(ASDisplayNode *)node; -- (NSString *)name; @end /** CALayer(AsyncDisplayKit) defines convenience method for adding sub-ASDisplayNode to a CALayer. */ @@ -696,7 +695,6 @@ typedef NS_OPTIONS(NSUInteger, ASInterfaceState) * @param node The node to be added. */ - (void)addSubnode:(ASDisplayNode *)node; -- (NSString *)name; @end @interface ASDisplayNode (Deprecated) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 7758561d96..ed7b097097 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2279,11 +2279,6 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode"; } } -- (NSString *)name -{ - return self.asyncdisplaykit_node.name; -} - @end @implementation CALayer (AsyncDisplayKit) @@ -2293,11 +2288,6 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode"; [self addSublayer:node.layer]; } -- (NSString *)name -{ - return self.asyncdisplaykit_node.name; -} - @end diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index c49f56a660..04e7885ddb 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -36,11 +36,11 @@ static CALayer *layerWithName(NSString *name) { } static NSString *orderStringFromSublayers(CALayer *l) { - return [[l.sublayers valueForKey:@"name"] componentsJoinedByString:@","]; + return [[[l.sublayers valueForKey:@"asyncdisplaykit_node"] valueForKey:@"name"] componentsJoinedByString:@","]; } static NSString *orderStringFromSubviews(UIView *v) { - return [[v.subviews valueForKey:@"name"] componentsJoinedByString:@","]; + return [[[v.subviews valueForKey:@"asyncdisplaykit_node"] valueForKey:@"name"] componentsJoinedByString:@","]; } static NSString *orderStringFromSubnodes(ASDisplayNode *n) {