mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Move RCTParagraphTextView drawing to contentView (#46081)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46081 This change fixes an issue that has been reported by OSS where a Text with both background color and borderWidth is not rendered properly. The reason is that `RCTParagraphComponentView` uses the `drawRect` method which draws the text in the main view layer, while the parent `RCTViewComponentView` can apply an extraLayer on top of the base layer, drawing on top of the text. This change moves the drawing of the text to an auxiliary view, `RCTParagraphTextView`, that is set as contentView of the `RCTParagraphView`. In this way, the text is drawn in a different view and can't be covered by the `_borderLayer` ## Changelog: [Internal] - Introduce a RCTParagraphTextView to draw the text Reviewed By: joevilches Differential Revision: D61431369 fbshipit-source-id: 05467167186411fe42312f2ed956f5b5336de019
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0f4a405f28
commit
f4609dbb5f
+76
-34
@@ -24,6 +24,16 @@
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
// ParagraphTextView is an auxiliary view we set as contentView so the drawing
|
||||
// can happen on top of the layers manipulated by RCTViewComponentView (the parent view)
|
||||
@interface RCTParagraphTextView : UIView
|
||||
|
||||
@property (nonatomic) ParagraphShadowNode::ConcreteState::Shared state;
|
||||
@property (nonatomic) ParagraphAttributes paragraphAttributes;
|
||||
@property (nonatomic) LayoutMetrics layoutMetrics;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTParagraphComponentView () <UIEditMenuInteractionDelegate>
|
||||
|
||||
@property (nonatomic, nullable) UIEditMenuInteraction *editMenuInteraction API_AVAILABLE(ios(16.0));
|
||||
@@ -35,7 +45,7 @@ using namespace facebook::react;
|
||||
ParagraphAttributes _paragraphAttributes;
|
||||
RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
|
||||
UILongPressGestureRecognizer *_longPressGestureRecognizer;
|
||||
CAShapeLayer *_highlightLayer;
|
||||
RCTParagraphTextView *_textView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
@@ -45,6 +55,9 @@ using namespace facebook::react;
|
||||
|
||||
self.opaque = NO;
|
||||
self.contentMode = UIViewContentModeRedraw;
|
||||
_textView = [RCTParagraphTextView new];
|
||||
_textView.backgroundColor = UIColor.clearColor;
|
||||
self.contentView = _textView;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -91,6 +104,7 @@ using namespace facebook::react;
|
||||
const auto &newParagraphProps = static_cast<const ParagraphProps &>(*props);
|
||||
|
||||
_paragraphAttributes = newParagraphProps.paragraphAttributes;
|
||||
_textView.paragraphAttributes = _paragraphAttributes;
|
||||
|
||||
if (newParagraphProps.isSelectable != oldParagraphProps.isSelectable) {
|
||||
if (newParagraphProps.isSelectable) {
|
||||
@@ -106,7 +120,20 @@ using namespace facebook::react;
|
||||
- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState
|
||||
{
|
||||
_state = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(state);
|
||||
[self setNeedsDisplay];
|
||||
_textView.state = _state;
|
||||
[_textView setNeedsDisplay];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
||||
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
|
||||
{
|
||||
// Using stored `_layoutMetrics` as `oldLayoutMetrics` here to avoid
|
||||
// re-applying individual sub-values which weren't changed.
|
||||
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:_layoutMetrics];
|
||||
_textView.layoutMetrics = _layoutMetrics;
|
||||
[_textView setNeedsDisplay];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
@@ -116,40 +143,11 @@ using namespace facebook::react;
|
||||
_accessibilityProvider = nil;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (!_state) {
|
||||
return;
|
||||
}
|
||||
[super layoutSubviews];
|
||||
|
||||
auto textLayoutManager = _state->getData().layoutManager.lock();
|
||||
|
||||
if (!textLayoutManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
|
||||
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
|
||||
paragraphAttributes:_paragraphAttributes
|
||||
frame:frame
|
||||
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;
|
||||
}
|
||||
}];
|
||||
_textView.frame = self.bounds;
|
||||
}
|
||||
|
||||
#pragma mark - Accessibility
|
||||
@@ -324,3 +322,47 @@ Class<RCTComponentViewProtocol> RCTParagraphCls(void)
|
||||
{
|
||||
return RCTParagraphComponentView.class;
|
||||
}
|
||||
|
||||
@implementation RCTParagraphTextView {
|
||||
RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
|
||||
UILongPressGestureRecognizer *_longPressGestureRecognizer;
|
||||
CAShapeLayer *_highlightLayer;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
if (!_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto textLayoutManager = _state->getData().layoutManager.lock();
|
||||
|
||||
if (!textLayoutManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
|
||||
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
|
||||
paragraphAttributes:_paragraphAttributes
|
||||
frame:frame
|
||||
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;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user