diff --git a/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m b/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m index fa86a458970a95..c92b2e94c6a1b5 100644 --- a/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m +++ b/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m @@ -66,6 +66,15 @@ - (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFlo NSLayoutManager *layoutManager = self.layoutManagers.firstObject; NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + // A workaround for truncatedGlyphRangeInLineFragmentForGlyphAtIndex returning NSNotFound when text has only + // one character and it gets truncated + if ([self length] == 1) { + CGSize characterSize = [[self string] sizeWithAttributes:[self attributesAtIndex:0 effectiveRange:nil]]; + if (characterSize.width > size.width) { + return RCTTextSizeComparisonLarger; + } + } + [layoutManager ensureLayoutForTextContainer:textContainer]; // Does it fit the text container? diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index be27e77d13956a..66c3b15c92c94f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -75,6 +75,7 @@ public long measure( "Spannable element has not been prepared in onBeforeLayout"); Layout layout = measureSpannedText(text, width, widthMode); + TextPaint paint = new TextPaint(sTextPaintInstance); if (mAdjustsFontSizeToFit) { int initialFontSize = mTextAttributes.getEffectiveFontSize(); @@ -83,8 +84,9 @@ public long measure( int minimumFontSize = (int) Math.max(mMinimumFontScale * initialFontSize, PixelUtil.toPixelFromDIP(4)); while (currentFontSize > minimumFontSize - && (mNumberOfLines != ReactConstants.UNSET && layout.getLineCount() > mNumberOfLines - || heightMode != YogaMeasureMode.UNDEFINED && layout.getHeight() > height)) { + && ((mNumberOfLines != ReactConstants.UNSET && layout.getLineCount() > mNumberOfLines + || heightMode != YogaMeasureMode.UNDEFINED && layout.getHeight() > height) + || (text.length() == 1 && paint.measureText(text.toString()) > width))) { // TODO: We could probably use a smarter algorithm here. This will require 0(n) // measurements // based on the number of points the font size needs to be reduced by. @@ -94,13 +96,15 @@ public long measure( ReactAbsoluteSizeSpan[] sizeSpans = text.getSpans(0, text.length(), ReactAbsoluteSizeSpan.class); for (ReactAbsoluteSizeSpan span : sizeSpans) { + int newSize = (int) Math.max((span.getSize() * ratio), minimumFontSize); text.setSpan( - new ReactAbsoluteSizeSpan( - (int) Math.max((span.getSize() * ratio), minimumFontSize)), + new ReactAbsoluteSizeSpan(newSize), text.getSpanStart(span), text.getSpanEnd(span), text.getSpanFlags(span)); text.removeSpan(span); + + paint.setTextSize(newSize); } layout = measureSpannedText(text, width, widthMode); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index 6e22ae9f409651..4861e2729dd89a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -582,7 +582,8 @@ private static Layout createLayout( && maximumNumberOfLines != 0 && layout.getLineCount() > maximumNumberOfLines) || (heightYogaMeasureMode != YogaMeasureMode.UNDEFINED - && layout.getHeight() > height))) { + && layout.getHeight() > height) + || (text.length() == 1 && layout.getPaint().measureText(text.toString()) > width))) { // TODO: We could probably use a smarter algorithm here. This will require 0(n) // measurements based on the number of points the font size needs to be reduced by. currentFontSize -= Math.max(1, (int) PixelUtil.toPixelFromDIP(1)); @@ -600,6 +601,7 @@ private static Layout createLayout( text.getSpanFlags(span)); text.removeSpan(span); } + boring = BoringLayout.isBoring(text, paint); layout = createLayout( text,