add support for text highlighting (#43386)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/43386

Changes:
- fixes `RCTAttributedTextUtils` to set `RCTAttributedStringIsHighlightedAttributeName` attribute according to `isHighlighted` textAttribute value.
- adds block to `drawAttributedString` and passed highlighted bezier curve to it.
- updates `drawRect` to visually highlight selected text.

## Changelog:
[iOS][Fixed] - Fixed text highlighting in the New Architecture

Reviewed By: sammy-SC

Differential Revision: D54594472

fbshipit-source-id: ed454e3a1660fa76d96cb131e33fba1c05f47776
This commit is contained in:
Alexey Litvinov
2024-03-08 09:24:45 -08:00
committed by Facebook GitHub Bot
parent 7bb204a160
commit eadcebbb3e
4 changed files with 52 additions and 3 deletions
@@ -35,6 +35,7 @@ using namespace facebook::react;
ParagraphAttributes _paragraphAttributes;
RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
UILongPressGestureRecognizer *_longPressGestureRecognizer;
CAShapeLayer *_highlightLayer;
}
- (instancetype)initWithFrame:(CGRect)frame
@@ -132,7 +133,21 @@ using namespace facebook::react;
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
paragraphAttributes:_paragraphAttributes
frame:frame
textStorage:unwrapManagedObject(nsTextStorage)];
textStorage:unwrapManagedObject(nsTextStorage)
drawHighlightPath:^(UIBezierPath *highlightPath) {
if (highlightPath) {
if (!self->_highlightLayer) {
self->_highlightLayer = [CAShapeLayer layer];
self->_highlightLayer.fillColor = [UIColor colorWithWhite:0 alpha:0.25].CGColor;
[self.layer addSublayer:self->_highlightLayer];
}
self->_highlightLayer.position = frame.origin;
self->_highlightLayer.path = highlightPath.CGPath;
} else {
[self->_highlightLayer removeFromSuperlayer];
self->_highlightLayer = nil;
}
}];
}
#pragma mark - Accessibility
@@ -285,7 +285,7 @@ NSDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttributes(c
}
// Special
if (textAttributes.isHighlighted) {
if (textAttributes.isHighlighted.value_or(false)) {
attributes[RCTAttributedStringIsHighlightedAttributeName] = @YES;
}
@@ -43,7 +43,8 @@ using RCTTextLayoutFragmentEnumerationBlock =
- (void)drawAttributedString:(facebook::react::AttributedString)attributedString
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame
textStorage:(NSTextStorage *_Nullable)textStorage;
textStorage:(NSTextStorage *_Nullable)textStorage
drawHighlightPath:(void (^_Nullable)(UIBezierPath *highlightPath))block;
- (facebook::react::LinesMeasurements)getLinesForAttributedString:(facebook::react::AttributedString)attributedString
paragraphAttributes:
@@ -76,6 +76,7 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame
textStorage:(NSTextStorage *_Nullable)textStorage
drawHighlightPath:(void (^_Nullable)(UIBezierPath *highlightPath))block
{
BOOL createdStorageForFrame = NO;
@@ -118,6 +119,38 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
#if TARGET_OS_MACCATALYST
CGContextRestoreGState(context);
#endif
if (block != nil) {
__block UIBezierPath *highlightPath = nil;
NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
[textStorage
enumerateAttribute:RCTAttributedStringIsHighlightedAttributeName
inRange:characterRange
options:0
usingBlock:^(NSNumber *value, NSRange range, __unused BOOL *stop) {
if (!value.boolValue) {
return;
}
[layoutManager
enumerateEnclosingRectsForGlyphRange:range
withinSelectedGlyphRange:range
inTextContainer:textContainer
usingBlock:^(CGRect enclosingRect, __unused BOOL *anotherStop) {
UIBezierPath *path = [UIBezierPath
bezierPathWithRoundedRect:CGRectInset(enclosingRect, -2, -2)
cornerRadius:2];
if (highlightPath) {
[highlightPath appendPath:path];
} else {
highlightPath = path;
}
}];
}];
block(highlightPath);
}
}
- (LinesMeasurements)getLinesForAttributedString:(AttributedString)attributedString