Size height of Android Text component based on includeFontPadding style

Summary:
Overview -

This PR resolves the issue described in #14606. This PR makes Text components take into account the includeFontPadding property when calculating their size.

Background -

Currently, on Android, when includeFontPadding is set to false, the React Text component does not adjust its height. This makes it difficult to lay out other components at a precise spacing relative to a Text component.

iOS calculates the height of a UILabel based on the font's descent + ascent.

Android lets you choose whether to calculate the height of a TextView based on the font's top + bottom (includeFontPadding=true) or ascent + descent (includeFontPadding=false).

In order for a text component to be the same size on iOS and Android (relative to the rest of the layout in points and dips), one should set includeFontPadding=false on Android - but the React Text component needs to take this property into account when sizing itself for this to work.

Please see this stack overflow post for a visual explanation of the difference between a font's ascent/descent and top/bottom - https://stackoverflow.com/questions/27631736/meaning-of-top-ascent-baseline-descent-bottom-and-leading-in-androids-font

Testing -

Please see the attached screenshots to see the height difference of a Text component with this PR when includeFontPadding is true vs false.

The font I am using has an ascent + descent = em-size so that the height of the Text component will be equal to the font-size for a single line of text. This is to clearly show the additional height that includeFontPadding=true adds to the Text component.

For Text components that are styled in the same way,

When includeFontPadding=true, height = ~29.714 dips
When includeFontPadding=false, height= 24 dips

<img width="342" alt="includefontpaddingtrue" src="https://user-images.githubusercontent.com/1437344/27299391-3eec9de0-54fa-11e7-81d5-d0aeb40e8e27.png">

<img width="346" alt="includefontpaddingfalse" src="https://user-images.githubusercontent.com/1437344/27299401-45c95248-54fa-11e7-98d7-17dd152d3cb8.png">
Closes https://github.com/facebook/react-native/pull/14609

Reviewed By: AaaChiuuu

Differential Revision: D5587602

Pulled By: achen1

fbshipit-source-id: 6d2f12ba72ec7462676645519cd27820279278eb
This commit is contained in:
Misha Greenberg 2017-08-18 15:25:12 -07:00 committed by Facebook Github Bot
parent f6de2e4a9b
commit 9f5bdd7b49
4 changed files with 21 additions and 8 deletions

View File

@ -57,6 +57,7 @@ import com.facebook.react.uimanager.annotations.ReactProp;
private float mSpacingAdd = 0.0f;
private int mNumberOfLines = Integer.MAX_VALUE;
private int mAlignment = Gravity.NO_GRAVITY;
private boolean mIncludeFontPadding = true;
public RCTText() {
setMeasureFunction(this);
@ -94,7 +95,7 @@ import com.facebook.react.uimanager.annotations.ReactProp;
(int) Math.ceil(width),
widthMode,
TextUtils.TruncateAt.END,
true,
mIncludeFontPadding,
mNumberOfLines,
mNumberOfLines == 1,
text,
@ -158,7 +159,7 @@ import com.facebook.react.uimanager.annotations.ReactProp;
(int) Math.ceil(right - left),
YogaMeasureMode.EXACTLY,
TextUtils.TruncateAt.END,
true,
mIncludeFontPadding,
mNumberOfLines,
mNumberOfLines == 1,
mText,
@ -223,6 +224,11 @@ import com.facebook.react.uimanager.annotations.ReactProp;
notifyChanged(true);
}
@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
public void setIncludeFontPadding(boolean includepad) {
mIncludeFontPadding = includepad;
}
@Override
/* package */ void updateNodeRegion(
float left,

View File

@ -92,6 +92,7 @@ public class ViewProps {
public static final String TEXT_BREAK_STRATEGY = "textBreakStrategy";
public static final String ALLOW_FONT_SCALING = "allowFontScaling";
public static final String INCLUDE_FONT_PADDING = "includeFontPadding";
public static final String BORDER_WIDTH = "borderWidth";
public static final String BORDER_LEFT_WIDTH = "borderLeftWidth";

View File

@ -258,12 +258,12 @@ public class ReactTextShadowNode extends LayoutShadowNode {
Layout.Alignment.ALIGN_NORMAL,
1.f,
0.f,
true);
mIncludeFontPadding);
} else {
layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
.setLineSpacing(0.f, 1.f)
.setIncludePad(true)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
@ -280,7 +280,7 @@ public class ReactTextShadowNode extends LayoutShadowNode {
1.f,
0.f,
boring,
true);
mIncludeFontPadding);
} else {
// Is used for multiline, boring text and the width is known.
@ -292,12 +292,12 @@ public class ReactTextShadowNode extends LayoutShadowNode {
Layout.Alignment.ALIGN_NORMAL,
1.f,
0.f,
true);
mIncludeFontPadding);
} else {
layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
.setLineSpacing(0.f, 1.f)
.setIncludePad(true)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
@ -351,6 +351,7 @@ public class ReactTextShadowNode extends LayoutShadowNode {
private boolean mIsUnderlineTextDecorationSet = false;
private boolean mIsLineThroughTextDecorationSet = false;
private boolean mIncludeFontPadding = true;
/**
* mFontStyle can be {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
@ -559,6 +560,11 @@ public class ReactTextShadowNode extends LayoutShadowNode {
}
}
@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
public void setIncludeFontPadding(boolean includepad) {
mIncludeFontPadding = includepad;
}
@ReactProp(name = ViewProps.TEXT_DECORATION_LINE)
public void setTextDecorationLine(@Nullable String textDecorationLineString) {
mIsUnderlineTextDecorationSet = false;

View File

@ -152,7 +152,7 @@ public class ReactTextViewManager extends BaseViewManager<ReactTextView, ReactTe
view.setBorderColor(SPACING_TYPES[index], rgbComponent, alphaComponent);
}
@ReactProp(name = "includeFontPadding", defaultBoolean = true)
@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
public void setIncludeFontPadding(ReactTextView view, boolean includepad) {
view.setIncludeFontPadding(includepad);
}