From 7fa810c77fc5dfa535d23fa1e1ca1a4460b19284 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Sun, 10 Apr 2016 00:19:00 -0700 Subject: [PATCH] [ASControlNode] modified hitTestDebug tool vizualize clipping of .clipsToBounds & fixed bug - added orange overlay edge highlighting if tapable area clipped by .clipsToBounds of any parent in the hierarchy - fixed bug in comparison of child / parent rect edges --- AsyncDisplayKit/ASControlNode.mm | 77 ++++++++++++++++--------- AsyncDisplayKit/AsyncDisplayKit+Debug.h | 2 + 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/AsyncDisplayKit/ASControlNode.mm b/AsyncDisplayKit/ASControlNode.mm index 02b96157d9..9a2fd276a4 100644 --- a/AsyncDisplayKit/ASControlNode.mm +++ b/AsyncDisplayKit/ASControlNode.mm @@ -470,6 +470,7 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v CGRect originalRect = UIEdgeInsetsInsetRect(self.bounds, [self hitTestSlop]); CGRect intersectRect = originalRect; UIRectEdge clippedEdges = UIRectEdgeNone; + UIRectEdge clipsToBoundsClippedEdges = UIRectEdgeNone; CALayer *layer = self.layer; CALayer *intersectLayer = layer; CALayer *intersectSuperlayer = layer.superlayer; @@ -479,14 +480,20 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v while (intersectSuperlayer && ![intersectSuperlayer.delegate respondsToSelector:@selector(contentOffset)]) { // Get our parent's tappable bounds. If the parent has an associated node, consider hitTestSlop, as it will extend its pointInside:. CGRect parentHitRect = intersectSuperlayer.bounds; + BOOL parentClipsToBounds = intersectSuperlayer.masksToBounds; ASDisplayNode *parentNode = ASLayerToDisplayNode(intersectSuperlayer); - if (parentNode) { + if (parentNode && !parentClipsToBounds) { parentHitRect = UIEdgeInsetsInsetRect(parentHitRect, [parentNode hitTestSlop]); } // Convert our current rectangle to parent coordinates, and intersect with the parent's hit rect. CGRect intersectRectInParentCoordinates = [intersectSuperlayer convertRect:intersectRect fromLayer:intersectLayer]; intersectRect = CGRectIntersection(parentHitRect, intersectRectInParentCoordinates); + if (parentClipsToBounds) { + if (!CGSizeEqualToSize(parentHitRect.size, intersectRectInParentCoordinates.size)) { + clipsToBoundsClippedEdges = [self setEdgesOfIntersectionForChildRect:intersectRectInParentCoordinates parentRect:parentHitRect rectEdge:clipsToBoundsClippedEdges]; + } + } // Advance up the tree. intersectLayer = intersectSuperlayer; @@ -499,41 +506,19 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v // determine which edges were clipped if (!CGSizeEqualToSize(originalRect.size, finalRect.size)) { - if (originalRect.origin.y != finalRect.origin.y) { - clippedEdges |= UIRectEdgeTop; - } - if (originalRect.origin.x != finalRect.origin.x) { - clippedEdges |= UIRectEdgeLeft; - } - if (CGRectGetMaxY(originalRect) != CGRectGetMaxY(finalRect)) { - clippedEdges |= UIRectEdgeBottom; - } - if (CGRectGetMaxX(originalRect) != CGRectGetMaxX(finalRect)) { - clippedEdges |= UIRectEdgeRight; - } + clippedEdges = [self setEdgesOfIntersectionForChildRect:originalRect parentRect:finalRect rectEdge:clippedEdges]; const CGFloat borderWidth = 2.0; - const UIColor *borderColor = [UIColor colorWithRed:30/255.0 green:90/255.0 blue:50/255.0 alpha:0.7]; + UIColor *superhitTestSlopClipsBorderColor = [UIColor colorWithRed:30/255.0 green:90/255.0 blue:50/255.0 alpha:0.7]; + UIColor *superClipsToBoundsBorderColor = [[UIColor orangeColor] colorWithAlphaComponent:0.8]; CGRect imgRect = CGRectMake(0, 0, 2.0 * borderWidth + 1.0, 2.0 * borderWidth + 1.0); UIGraphicsBeginImageContext(imgRect.size); [fillColor setFill]; UIRectFill(imgRect); - [borderColor setFill]; - - if (clippedEdges & UIRectEdgeTop) { - UIRectFill(CGRectMake(0.0, 0.0, imgRect.size.width, borderWidth)); - } - if (clippedEdges & UIRectEdgeLeft) { - UIRectFill(CGRectMake(0.0, 0.0, borderWidth, imgRect.size.height)); - } - if (clippedEdges & UIRectEdgeBottom) { - UIRectFill(CGRectMake(0.0, imgRect.size.height - borderWidth, imgRect.size.width, borderWidth)); - } - if (clippedEdges & UIRectEdgeRight) { - UIRectFill(CGRectMake(imgRect.size.width - borderWidth, 0.0, borderWidth, imgRect.size.height)); - } + [self drawEdgeIfClippedWithEdges:clippedEdges color:superhitTestSlopClipsBorderColor borderWidth:borderWidth imgRect:imgRect]; + [self drawEdgeIfClippedWithEdges:clipsToBoundsClippedEdges color:superClipsToBoundsBorderColor borderWidth:borderWidth imgRect:imgRect]; UIImage *debugHighlightImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); @@ -550,6 +535,42 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v } } +- (UIRectEdge)setEdgesOfIntersectionForChildRect:(CGRect)childRect parentRect:(CGRect)parentRect rectEdge:(UIRectEdge)rectEdge +{ + if (childRect.origin.y < parentRect.origin.y) { + rectEdge |= UIRectEdgeTop; + } + if (childRect.origin.x < parentRect.origin.x) { + rectEdge |= UIRectEdgeLeft; + } + if (CGRectGetMaxY(childRect) > CGRectGetMaxY(parentRect)) { + rectEdge |= UIRectEdgeBottom; + } + if (CGRectGetMaxX(childRect) > CGRectGetMaxX(parentRect)) { + rectEdge |= UIRectEdgeRight; + } + + return rectEdge; +} + +- (void)drawEdgeIfClippedWithEdges:(UIRectEdge)rectEdge color:(UIColor *)color borderWidth:(CGFloat)borderWidth imgRect:(CGRect)imgRect +{ + [color setFill]; + + if (rectEdge & UIRectEdgeTop) { + UIRectFill(CGRectMake(0.0, 0.0, imgRect.size.width, borderWidth)); + } + if (rectEdge & UIRectEdgeLeft) { + UIRectFill(CGRectMake(0.0, 0.0, borderWidth, imgRect.size.height)); + } + if (rectEdge & UIRectEdgeBottom) { + UIRectFill(CGRectMake(0.0, imgRect.size.height - borderWidth, imgRect.size.width, borderWidth)); + } + if (rectEdge & UIRectEdgeRight) { + UIRectFill(CGRectMake(imgRect.size.width - borderWidth, 0.0, borderWidth, imgRect.size.height)); + } +} + + (void)setEnableHitTestDebug:(BOOL)enable { _enableHitTestDebug = enable; diff --git a/AsyncDisplayKit/AsyncDisplayKit+Debug.h b/AsyncDisplayKit/AsyncDisplayKit+Debug.h index 4192d67398..ba6897b9b0 100644 --- a/AsyncDisplayKit/AsyncDisplayKit+Debug.h +++ b/AsyncDisplayKit/AsyncDisplayKit+Debug.h @@ -13,6 +13,8 @@ /** Class method to enable a visualization overlay of the tapable area on the ASControlNode. For app debugging purposes only. + Overlay = translucent green color, edges clipped by hitTestDebug of any parent in the hierarchy = dark green bordered edge, + edges clipped by clipToBounds = YES of any parent in the hierarchy = orange bordered edge. @param enable Specify YES to make this debug feature enabled when messaging the ASControlNode class. */ + (void)setEnableHitTestDebug:(BOOL)enable;