Implement onPress for Virtual Text nodes

Summary:
When text nodes are nested, as below, `onPress` handlers need to be correctly invoked:
```
render() {
  return (
    <Text onPress={() => console.warn('hi')}>
      hi
      <Text onPress={() => console.warn('ramanpreet')}>ramanpreet</Text>
    </Text>
  );
}
```

In the above example, clicking on "hi" should warn "hi", and clicking on "ramanpreet" should warn "ramanpreet". This diff implements that behaviour.

Reviewed By: shergin

Differential Revision: D9696905

fbshipit-source-id: 2daf24e76c3b3c37aa36cd1540e54876a367faf7
This commit is contained in:
Ramanpreet Nara 2018-09-10 11:19:28 -07:00 committed by Facebook Github Bot
parent 4c7cf13678
commit 7eb82f32a2
3 changed files with 56 additions and 1 deletions

View File

@ -84,4 +84,28 @@ using namespace facebook::react;
return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString()); return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString());
} }
@end - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
{
if (!_paragraphLocalData) {
return _eventEmitter;
}
SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager();
RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager();
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
SharedShadowNode textShadowNode = [nativeTextLayoutManager getParentShadowNodeWithAttributeString:_paragraphLocalData->getAttributedString()
paragraphAttributes:_paragraphAttributes
frame:frame
atPoint:point];
if (!textShadowNode) {
return _eventEmitter;
}
SharedEventEmitter eventEmitter = textShadowNode->getEventEmitter();
assert(std::dynamic_pointer_cast<const TouchEventEmitter>(eventEmitter));
return std::static_pointer_cast<const TouchEventEmitter>(eventEmitter);
}
@end

View File

@ -27,6 +27,11 @@ NS_ASSUME_NONNULL_BEGIN
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame; frame:(CGRect)frame;
- (facebook::react::SharedShadowNode)getParentShadowNodeWithAttributeString:(facebook::react::AttributedString)attributedString
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame
atPoint:(CGPoint)point;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -93,4 +93,30 @@ static NSLineBreakMode RCTNSLineBreakModeFromWritingDirection(EllipsizeMode elli
return textStorage; return textStorage;
} }
- (SharedShadowNode)getParentShadowNodeWithAttributeString:(AttributedString)attributedString
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame
atPoint:(CGPoint)point {
NSTextStorage *textStorage =
[self _textStorageAndLayoutManagerWithAttributesString:RCTNSAttributedStringFromAttributedString(attributedString)
paragraphAttributes:paragraphAttributes
size:frame.size];
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
CGFloat fraction;
NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:&fraction];
// If the point is not before (fraction == 0.0) the first character and not
// after (fraction == 1.0) the last character, then the attribute is valid.
if (textStorage.length > 0 && (fraction > 0 || characterIndex > 0) && (fraction < 1 || characterIndex < textStorage.length - 1)) {
RCTSharedShadowNodeWrapper *parentShadowNode = (RCTSharedShadowNodeWrapper *)[textStorage attribute:RCTAttributedStringParentShadowNode atIndex:characterIndex effectiveRange:NULL];
return parentShadowNode.node;
}
return nil;
}
@end @end