diff --git a/AsyncDisplayKit/ASCellNode.h b/AsyncDisplayKit/ASCellNode.h index 1893f92a30..12cc6302f4 100644 --- a/AsyncDisplayKit/ASCellNode.h +++ b/AsyncDisplayKit/ASCellNode.h @@ -20,6 +20,15 @@ //@property (atomic, retain) UIColor *backgroundColor; @property (nonatomic) UITableViewCellSelectionStyle selectionStyle; +/* + * ASCellNode must forward touch events in order for UITableView and UICollectionView tap handling to work. Overriding + * these methods (e.g. for highlighting) requires the super method be called. + */ +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ASDISPLAYNODE_REQUIRES_SUPER; +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event ASDISPLAYNODE_REQUIRES_SUPER; +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event ASDISPLAYNODE_REQUIRES_SUPER; +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event ASDISPLAYNODE_REQUIRES_SUPER; + @end diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index 6efe37045a..3c7559f85f 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -8,8 +8,9 @@ #import "ASCellNode.h" -#import "ASDisplayNode+Subclasses.h" -#import "ASTextNode.h" +#import +#import +#import #pragma mark - @@ -28,12 +29,52 @@ return self; } +- (instancetype)initWithLayerBlock:(ASDisplayNodeLayerBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + +- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + - (void)setLayerBacked:(BOOL)layerBacked { // ASRangeController expects ASCellNodes to be view-backed. (Layer-backing is supported on ASCellNode subnodes.) ASDisplayNodeAssert(!layerBacked, @"ASCellNode does not support layer-backing."); } +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + ASDisplayNodeAssertMainThread(); + ASDisplayNodeAssert([self.view isKindOfClass:_ASDisplayView.class], @"ASCellNode views must be of type _ASDisplayView"); + [(_ASDisplayView *)self.view __forwardTouchesBegan:touches withEvent:event]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + ASDisplayNodeAssertMainThread(); + ASDisplayNodeAssert([self.view isKindOfClass:_ASDisplayView.class], @"ASCellNode views must be of type _ASDisplayView"); + [(_ASDisplayView *)self.view __forwardTouchesMoved:touches withEvent:event]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + ASDisplayNodeAssertMainThread(); + ASDisplayNodeAssert([self.view isKindOfClass:_ASDisplayView.class], @"ASCellNode views must be of type _ASDisplayView"); + [(_ASDisplayView *)self.view __forwardTouchesEnded:touches withEvent:event]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + ASDisplayNodeAssertMainThread(); + ASDisplayNodeAssert([self.view isKindOfClass:_ASDisplayView.class], @"ASCellNode views must be of type _ASDisplayView"); + [(_ASDisplayView *)self.view __forwardTouchesCancelled:touches withEvent:event]; +} + @end diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 0fba57ae99..614e4c833b 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1424,22 +1424,22 @@ static NSInteger incrementIfFound(NSInteger i) { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - // subclass hook + // subclass hook } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - // subclass hook + // subclass hook } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - // subclass hook + // subclass hook } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - // subclass hook + // subclass hook } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index e5899f51c4..0b757d1752 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -85,6 +85,18 @@ return self; } +- (instancetype)initWithLayerBlock:(ASDisplayNodeLayerBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + +- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + - (void)dealloc { _textKitComponents.textView.delegate = nil; diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index 11df02f9ab..76bd5b6cb4 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -94,6 +94,18 @@ return self; } +- (instancetype)initWithLayerBlock:(ASDisplayNodeLayerBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + +- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize { ASDN::MutexLocker l(_imageLock); diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 106fc6fa8a..d6d1a46a62 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -146,6 +146,18 @@ ASDISPLAYNODE_INLINE CGFloat ceilPixelValue(CGFloat f) return self; } +- (instancetype)initWithLayerBlock:(ASDisplayNodeLayerBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + +- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock +{ + ASDisplayNodeAssertNotSupported(); + return nil; +} + - (void)dealloc { if (_shadowColor != NULL) { diff --git a/AsyncDisplayKit/Details/_ASDisplayView.h b/AsyncDisplayKit/Details/_ASDisplayView.h index 940ddd6630..d2049a6b14 100644 --- a/AsyncDisplayKit/Details/_ASDisplayView.h +++ b/AsyncDisplayKit/Details/_ASDisplayView.h @@ -14,4 +14,11 @@ @interface _ASDisplayView : UIView +// These methods expose a way for ASDisplayNode touch events to let the view call super touch events +// Some UIKit mechanisms, like UITableView and UICollectionView selection handling, require this to work +- (void)__forwardTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)__forwardTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)__forwardTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)__forwardTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; + @end diff --git a/AsyncDisplayKit/Details/_ASDisplayView.mm b/AsyncDisplayKit/Details/_ASDisplayView.mm index 9add41a5c2..8a71013fbe 100644 --- a/AsyncDisplayKit/Details/_ASDisplayView.mm +++ b/AsyncDisplayKit/Details/_ASDisplayView.mm @@ -151,38 +151,58 @@ #pragma mark - Event Handling + UIResponder Overrides - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesBegan) { - [_node touchesBegan:touches withEvent:event]; - } else { - [super touchesBegan:touches withEvent:event]; - } + if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesBegan) { + [_node touchesBegan:touches withEvent:event]; + } else { + [super touchesBegan:touches withEvent:event]; + } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesMoved) { - [_node touchesMoved:touches withEvent:event]; - } else { - [super touchesMoved:touches withEvent:event]; - } + if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesMoved) { + [_node touchesMoved:touches withEvent:event]; + } else { + [super touchesMoved:touches withEvent:event]; + } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesEnded) { - [_node touchesEnded:touches withEvent:event]; - } else { - [super touchesEnded:touches withEvent:event]; - } + if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesEnded) { + [_node touchesEnded:touches withEvent:event]; + } else { + [super touchesEnded:touches withEvent:event]; + } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesCancelled) { - [_node touchesCancelled:touches withEvent:event]; - } else { - [super touchesCancelled:touches withEvent:event]; - } + if (_node.methodOverrides & ASDisplayNodeMethodOverrideTouchesCancelled) { + [_node touchesCancelled:touches withEvent:event]; + } else { + [super touchesCancelled:touches withEvent:event]; + } +} + +- (void)__forwardTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesBegan:touches withEvent:event]; +} + +- (void)__forwardTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesMoved:touches withEvent:event]; +} + +- (void)__forwardTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesEnded:touches withEvent:event]; +} + +- (void)__forwardTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesCancelled:touches withEvent:event]; } - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event