Skip to content

Commit dda7f82

Browse files
yungstersfacebook-github-bot
authored andcommitted
RN: Shrinkwrap Text Layout (Android)
Summary: When text is in a constrained parent view using `maxWidth`, long text may wrap. When the text wraps, the final width is dependent on the word breaking strategy and text content. This means that the text width is not necessarily `maxWidth`. However, the current way that we compute text layout does not shrinkwrap the text width as much as possible. This leads to visual gaps to the end-side of wrapped text. This changes the text layout slightly so that we use the length of the longest line. This bug only exists on Android. After this change, Android behaves like iOS. Changelog: [Android] [Fixed] - Fixed excessive space in Text view with word-wrapping Reviewed By: JoshuaGross, mdvacca Differential Revision: D21056031 fbshipit-source-id: e9b7793f2632caafcce69bc15bac61330b0ed958
1 parent 25ed045 commit dda7f82

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java

+15-5
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,22 @@ public long measure(
122122
}
123123
}
124124

125-
if (mNumberOfLines != UNSET && mNumberOfLines < layout.getLineCount()) {
126-
return YogaMeasureOutput.make(
127-
layout.getWidth(), layout.getLineBottom(mNumberOfLines - 1));
128-
} else {
129-
return YogaMeasureOutput.make(layout.getWidth(), layout.getHeight());
125+
final int lineCount =
126+
mNumberOfLines == UNSET
127+
? layout.getLineCount()
128+
: Math.min(mNumberOfLines, layout.getLineCount());
129+
130+
// Instead of using `layout.getWidth()` (which may yield a significantly larger width for
131+
// text that is wrapping), compute width using the longest line.
132+
float layoutWidth = 0;
133+
for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) {
134+
float lineWidth = layout.getLineWidth(lineIndex);
135+
if (lineWidth > layoutWidth) {
136+
layoutWidth = lineWidth;
137+
}
130138
}
139+
140+
return YogaMeasureOutput.make(layoutWidth, layout.getLineBottom(lineCount - 1));
131141
}
132142
};
133143

ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java

+14-8
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,20 @@ public static long measureText(
294294
? paragraphAttributes.getInt("maximumNumberOfLines")
295295
: UNSET;
296296

297-
int calculatedWidth = layout.getWidth();
298-
int calculatedHeight;
299-
if (maximumNumberOfLines != UNSET
300-
&& maximumNumberOfLines != 0
301-
&& maximumNumberOfLines < layout.getLineCount()) {
302-
calculatedHeight = layout.getLineBottom(maximumNumberOfLines - 1);
303-
} else {
304-
calculatedHeight = layout.getHeight();
297+
int calculatedLineCount =
298+
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
299+
? layout.getLineCount()
300+
: Math.min(maximumNumberOfLines, layout.getLineCount());
301+
302+
int calculatedHeight = layout.getLineBottom(calculatedLineCount - 1);
303+
// Instead of using `layout.getWidth()` (which may yield a significantly larger width for
304+
// text that is wrapping), compute width using the longest line.
305+
int calculatedWidth = 0;
306+
for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) {
307+
float lineWidth = layout.getLineWidth(lineIndex);
308+
if (lineWidth > calculatedWidth) {
309+
calculatedWidth = (int) Math.ceil(lineWidth);
310+
}
305311
}
306312

307313
// Calculate the positions of the attachments (views) that will be rendered inside the Spanned

0 commit comments

Comments
 (0)