Skip to content

Commit 6d24ee1

Browse files
BeeMargaridafacebook-github-bot
authored andcommitted
fix: apply font size to ReactTextView to fix ellipsis cut (#37248)
Summary: This PR aims to fix #36350. In certain cases, when the text is cut due to `numberOfLines`, the ellipsis appear cut. This is actually an Android bug, which was reported on their side [here](https://issuetracker.google.com/issues/278044456). This PR contains a workaround for it by applying the text size to the TextView directly instead of just the Spannable inside it. This solves all problems and it seems like it does not cause any regressions. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [FIXED] - Fix ellipsis being cut on certain font sizes Pull Request resolved: #37248 Test Plan: One piece of code where the problem could be replicated would be the one below, running on an Pixel 3A emulator. ```jsx <Text style={{padding: 27, fontSize: 30}} numberOfLines={1}> This text will be cut-off strangely in Android </Text> ``` RN-tester of the problem: | Before | With the fix | | --------------- | --------------- | | <img width="460" alt="Screenshot 2023-05-04 at 12 05 11" src="https://user-images.githubusercontent.com/25725586/236187961-d7841594-2d39-4cdc-aff9-a36f60fe6d15.png">| <img width="460" alt="Screenshot 2023-05-04 at 12 08 07" src="https://user-images.githubusercontent.com/25725586/236187999-e823beb5-0473-4940-894e-b3d2ff02c6cc.png"> | RN-Tester comparison: | Before | With the fix | | --------------- | --------------- | | <video src="https://user-images.githubusercontent.com/25725586/234273910-c6a9f55c-9a19-415d-b0cd-477c9087dac2.mp4"> | <video src="https://user-images.githubusercontent.com/25725586/234273973-ba6d5bd5-eba8-4eda-aefb-c926ea28c4e5.mp4"> | Reviewed By: javache Differential Revision: D45958303 Pulled By: NickGerleman fbshipit-source-id: 51f77702a82e60c0c18a29ee46b0aba4f37bcc28
1 parent f8a1f62 commit 6d24ee1

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ public void setAdjustFontSizeToFit(ReactTextView view, boolean adjustsFontSizeTo
7575
view.setAdjustFontSizeToFit(adjustsFontSizeToFit);
7676
}
7777

78+
@ReactProp(name = ViewProps.FONT_SIZE)
79+
public void setFontSize(ReactTextView view, float fontSize) {
80+
view.setFontSize(fontSize);
81+
}
82+
83+
@ReactProp(name = ViewProps.LETTER_SPACING, defaultFloat = Float.NaN)
84+
public void setLetterSpacing(ReactTextView view, float letterSpacing) {
85+
view.setLetterSpacing(letterSpacing);
86+
}
87+
7888
@ReactProp(name = ViewProps.TEXT_ALIGN_VERTICAL)
7989
public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignVertical) {
8090
if (textAlignVertical == null || "auto".equals(textAlignVertical)) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import android.text.TextUtils;
1919
import android.text.method.LinkMovementMethod;
2020
import android.text.util.Linkify;
21+
import android.util.TypedValue;
2122
import android.view.Gravity;
2223
import android.view.MotionEvent;
2324
import android.view.View;
@@ -57,6 +58,8 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
5758
private int mNumberOfLines;
5859
private TextUtils.TruncateAt mEllipsizeLocation;
5960
private boolean mAdjustsFontSizeToFit;
61+
private float mFontSize = Float.NaN;
62+
private float mLetterSpacing = Float.NaN;
6063
private int mLinkifyMaskType;
6164
private boolean mNotifyOnInlineViewLayout;
6265
private boolean mTextIsSelectable;
@@ -582,6 +585,29 @@ public void setAdjustFontSizeToFit(boolean adjustsFontSizeToFit) {
582585
mAdjustsFontSizeToFit = adjustsFontSizeToFit;
583586
}
584587

588+
public void setFontSize(float fontSize) {
589+
mFontSize =
590+
mAdjustsFontSizeToFit
591+
? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize))
592+
: (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
593+
594+
applyTextAttributes();
595+
}
596+
597+
public void setLetterSpacing(float letterSpacing) {
598+
if (Float.isNaN(letterSpacing)) {
599+
return;
600+
}
601+
602+
float letterSpacingPixels = PixelUtil.toPixelFromDIP(letterSpacing);
603+
604+
// `letterSpacingPixels` and `getEffectiveFontSize` are both in pixels,
605+
// yielding an accurate em value.
606+
mLetterSpacing = letterSpacingPixels / mFontSize;
607+
608+
applyTextAttributes();
609+
}
610+
585611
public void setEllipsizeLocation(TextUtils.TruncateAt ellipsizeLocation) {
586612
mEllipsizeLocation = ellipsizeLocation;
587613
}
@@ -651,4 +677,17 @@ protected boolean dispatchHoverEvent(MotionEvent event) {
651677

652678
return super.dispatchHoverEvent(event);
653679
}
680+
681+
private void applyTextAttributes() {
682+
// Workaround for an issue where text can be cut off with an ellipsis when
683+
// using certain font sizes and padding. Sets the provided text size and
684+
// letter spacing to ensure consistent rendering and prevent cut-off.
685+
if (!Float.isNaN(mFontSize)) {
686+
setTextSize(TypedValue.COMPLEX_UNIT_PX, mFontSize);
687+
}
688+
689+
if (!Float.isNaN(mLetterSpacing)) {
690+
super.setLetterSpacing(mLetterSpacing);
691+
}
692+
}
654693
}

packages/rn-tester/js/examples/Text/TextExample.android.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,10 @@ class TextExample extends React.Component<{...}> {
676676
Maximum of one line no matter now much I write here. If I keep
677677
writing it{"'"}ll just truncate after one line
678678
</Text>
679+
<Text style={{fontSize: 31}} numberOfLines={1}>
680+
Maximum of one line no matter now much I write here. If I keep
681+
writing it{"'"}ll just truncate after one line
682+
</Text>
679683
<Text numberOfLines={2} style={{marginTop: 20}}>
680684
Maximum of two lines no matter now much I write here. If I keep
681685
writing it{"'"}ll just truncate after two lines

0 commit comments

Comments
 (0)