From 70826dbafcb00c08e0038c5066e33848141be77b Mon Sep 17 00:00:00 2001 From: Adam Comella Date: Tue, 20 Nov 2018 00:09:46 -0800 Subject: [PATCH] iOS: Support inline view truncation (#21456) Summary: If text is truncated and an inline view appears after the truncation point, the user should not see the inline view. Instead, we have a bug such that the inline view is always visible at the end of the visible text. This commit fixes this by marking the inline view as hidden if it appears after the truncation point. This appears to be a regression. React Native used to have logic similar to what this commit is adding: https://github.com/facebook/react-native/blob/1e2a924ba60001c6f0587c7561536f00b2922cbf/Libraries/Text/RCTShadowText.m#L186-L192 **Before fix** Inline view (blue square) is visible even though it appears after the truncation point: ![image](https://user-images.githubusercontent.com/199935/46382038-d3a71200-c65d-11e8-8179-2ce4aad8d010.png) The full text being rendered was: ``` Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna ``` **After fix** Inline view is properly truncated: ![image](https://user-images.githubusercontent.com/199935/46382067-fdf8cf80-c65d-11e8-84ea-e2b71c229dae.png) **Test Plan** Tested that the inline view is hidden if it appears after the truncation point when `numberOfLines` is 1 and 2. Similarly, verified that the inline view is visible if it appears before the truncation point. **Release Notes** [IOS] [BUGFIX] [Text] - Fix case where inline view is visible even though it should have been truncated Adam Comella Microsoft Corp. Pull Request resolved: https://github.com/facebook/react-native/pull/21456 Differential Revision: D10182991 Pulled By: shergin fbshipit-source-id: a5bddddb1bb8672b61d4feaa04013a92c8224155 --- Libraries/Text/Text/RCTTextShadowView.m | 9 +++++++-- React/Modules/RCTUIManager.m | 7 +++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Libraries/Text/Text/RCTTextShadowView.m b/Libraries/Text/Text/RCTTextShadowView.m index 850879aa4f9ae7..d1baf9ccb152ec 100644 --- a/Libraries/Text/Text/RCTTextShadowView.m +++ b/Libraries/Text/Text/RCTTextShadowView.m @@ -290,6 +290,9 @@ - (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext RCTRoundPixelValue(attachmentSize.width), RCTRoundPixelValue(attachmentSize.height) }}; + + NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:range.location]; + BOOL viewIsTruncated = NSIntersectionRange(range, truncatedGlyphRange).length != 0; RCTLayoutContext localLayoutContext = layoutContext; localLayoutContext.absolutePosition.x += frame.origin.x; @@ -300,9 +303,11 @@ - (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext layoutDirection:self.layoutMetrics.layoutDirection layoutContext:localLayoutContext]; - // Reinforcing a proper frame origin for the Shadow View. RCTLayoutMetrics localLayoutMetrics = shadowView.layoutMetrics; - localLayoutMetrics.frame.origin = frame.origin; + localLayoutMetrics.frame.origin = frame.origin; // Reinforcing a proper frame origin for the Shadow View. + if (viewIsTruncated) { + localLayoutMetrics.displayType = RCTDisplayTypeNone; + } [shadowView layoutWithMetrics:localLayoutMetrics layoutContext:localLayoutContext]; } ]; diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 0760c7e57869c3..a8960f88de2e52 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -488,6 +488,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * UIUserInterfaceLayoutDirection layoutDirection; BOOL isNew; BOOL parentIsNew; + RCTDisplayType displayType; } RCTFrameData; // Construct arrays then hand off to main thread @@ -505,6 +506,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * layoutMetrics.layoutDirection, shadowView.isNewView, shadowView.superview.isNewView, + layoutMetrics.displayType }; } } @@ -566,6 +568,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * RCTLayoutAnimation *updatingLayoutAnimation = isNew ? nil : layoutAnimationGroup.updatingLayoutAnimation; BOOL shouldAnimateCreation = isNew && !frameData.parentIsNew; RCTLayoutAnimation *creatingLayoutAnimation = shouldAnimateCreation ? layoutAnimationGroup.creatingLayoutAnimation : nil; + BOOL isHidden = frameData.displayType == RCTDisplayTypeNone; void (^completion)(BOOL) = ^(BOOL finished) { completionsCalled++; @@ -581,6 +584,10 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * if (view.reactLayoutDirection != layoutDirection) { view.reactLayoutDirection = layoutDirection; } + + if (view.isHidden != isHidden) { + view.hidden = isHidden; + } if (creatingLayoutAnimation) {