From 025be8148a9abc533a8ae108e49cfd3f4512c581 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 23 Apr 2020 19:09:12 -0700 Subject: [PATCH] RN: Fix Text Layout Ignoring Parent Bounds Summary: Fixes text layout so that the parent bounds are correctly respected. This fixes two bugs: - **Parent width is not respected.** This was caused by the recent change to shrink-wrap text layout. - **Parent height is not respected.** This has always been a bug. After this change, Android will behave like iOS. Changelog: [Android] [Fixed] - Text layout no longer ignores parent bounds Reviewed By: mdvacca Differential Revision: D21199030 fbshipit-source-id: cc072bdcff64167db1f79b7bf965e57a7396cdf4 --- .../react/views/text/ReactTextShadowNode.java | 25 ++++++++++++--- .../react/views/text/TextLayoutManager.java | 31 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index b9fc8e75a255c4..ac84caae1e07d9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -130,14 +130,29 @@ public long measure( // Instead of using `layout.getWidth()` (which may yield a significantly larger width for // text that is wrapping), compute width using the longest line. float layoutWidth = 0; - for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { - float lineWidth = layout.getLineWidth(lineIndex); - if (lineWidth > layoutWidth) { - layoutWidth = lineWidth; + if (widthMode == YogaMeasureMode.EXACTLY) { + layoutWidth = width; + } else { + for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { + float lineWidth = layout.getLineWidth(lineIndex); + if (lineWidth > layoutWidth) { + layoutWidth = lineWidth; + } + } + if (widthMode == YogaMeasureMode.AT_MOST && layoutWidth > width) { + layoutWidth = width; + } + } + + float layoutHeight = height; + if (heightMode != YogaMeasureMode.EXACTLY) { + layoutHeight = layout.getLineBottom(lineCount - 1); + if (heightMode == YogaMeasureMode.AT_MOST && layoutHeight > height) { + layoutHeight = height; } } - return YogaMeasureOutput.make(layoutWidth, layout.getLineBottom(lineCount - 1)); + return YogaMeasureOutput.make(layoutWidth, layoutHeight); } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index 2213ec612823e0..bf5849bbe4a94f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -311,14 +311,28 @@ public static long measureText( ? layout.getLineCount() : Math.min(maximumNumberOfLines, layout.getLineCount()); - int calculatedHeight = layout.getLineBottom(calculatedLineCount - 1); // Instead of using `layout.getWidth()` (which may yield a significantly larger width for // text that is wrapping), compute width using the longest line. - int calculatedWidth = 0; - for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) { - float lineWidth = layout.getLineWidth(lineIndex); - if (lineWidth > calculatedWidth) { - calculatedWidth = (int) Math.ceil(lineWidth); + float calculatedWidth = 0; + if (widthYogaMeasureMode == YogaMeasureMode.EXACTLY) { + calculatedWidth = width; + } else { + for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) { + float lineWidth = layout.getLineWidth(lineIndex); + if (lineWidth > calculatedWidth) { + calculatedWidth = lineWidth; + } + } + if (widthYogaMeasureMode == YogaMeasureMode.AT_MOST && calculatedWidth > width) { + calculatedWidth = width; + } + } + + float calculatedHeight = height; + if (heightYogaMeasureMode != YogaMeasureMode.EXACTLY) { + calculatedHeight = layout.getLineBottom(calculatedLineCount - 1); + if (heightYogaMeasureMode == YogaMeasureMode.AT_MOST && calculatedHeight > height) { + calculatedHeight = height; } } @@ -356,7 +370,7 @@ public static long measureText( isRtlParagraph // Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect // values when the paragraph is RTL and `setSingleLine(true)`. - ? calculatedWidth - (int) layout.getLineWidth(line) + ? (int) calculatedWidth - (int) layout.getLineWidth(line) : (int) layout.getLineRight(line) - placeholderWidth; } else { // The direction of the paragraph may not be exactly the direction the string is heading @@ -379,7 +393,8 @@ public static long measureText( // The result is equivalent to bugless versions of // `getPrimaryHorizontal`/`getSecondaryHorizontal`. placeholderLeftPosition = - calculatedWidth - ((int) layout.getLineRight(line) - placeholderLeftPosition); + (int) calculatedWidth + - ((int) layout.getLineRight(line) - placeholderLeftPosition); } if (isRtlChar) { placeholderLeftPosition -= placeholderWidth;