Reverted commit D3751097
Summary: Setting the line height with the help of Android-provided StaticLayout is incorrect. A simple example app will display the following when `setLineSpacing(50.f, 0.f)` is set: {F62987699}. You'll notice that the height of the first line is a few pixels shorter than the other lines. So we use a custom LineHeightSpan instead, which needs to be applied to the text itself, and no height-related attributes need to be set on the TextView itself. Reviewed By: lexs Differential Revision: D3751097 fbshipit-source-id: 6c5a8d01a6dca4ff6eef9c3aadd1b550054432d2
This commit is contained in:
parent
ce6b13695a
commit
5cb8b97f3c
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.views.text;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.text.style.LineHeightSpan;
|
||||
|
||||
/**
|
||||
* We use a custom {@link LineHeightSpan}, because `lineSpacingExtra` is broken. Details here:
|
||||
* https://github.com/facebook/react-native/issues/7546
|
||||
*/
|
||||
public class CustomLineHeightSpan implements LineHeightSpan {
|
||||
private final float mHeight;
|
||||
|
||||
CustomLineHeightSpan(float height) {
|
||||
this.mHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chooseHeight(
|
||||
CharSequence text,
|
||||
int start,
|
||||
int end,
|
||||
int spanstartv,
|
||||
int v,
|
||||
Paint.FontMetricsInt fm) {
|
||||
fm.ascent = fm.top = 0;
|
||||
fm.descent = fm.bottom = (int) Math.ceil(mHeight);
|
||||
}
|
||||
}
|
|
@ -172,12 +172,6 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
textCSSNode.mTextShadowRadius,
|
||||
textCSSNode.mTextShadowColor)));
|
||||
}
|
||||
if (!Float.isNaN(textCSSNode.getEffectiveLineHeight())) {
|
||||
ops.add(new SetSpanOperation(
|
||||
start,
|
||||
end,
|
||||
new CustomLineHeightSpan(textCSSNode.getEffectiveLineHeight())));
|
||||
}
|
||||
ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textCSSNode.getReactTag())));
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +235,14 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
// technically, width should never be negative, but there is currently a bug in
|
||||
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;
|
||||
|
||||
float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
|
||||
float lineSpacingExtra = 0;
|
||||
float lineSpacingMultiplier = 1;
|
||||
if (!Float.isNaN(effectiveLineHeight)) {
|
||||
lineSpacingExtra = effectiveLineHeight;
|
||||
lineSpacingMultiplier = 0;
|
||||
}
|
||||
|
||||
if (boring == null &&
|
||||
(unconstrainedWidth ||
|
||||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
|
||||
|
@ -251,8 +253,8 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
textPaint,
|
||||
(int) Math.ceil(desiredWidth),
|
||||
Layout.Alignment.ALIGN_NORMAL,
|
||||
1.f,
|
||||
0.f,
|
||||
lineSpacingMultiplier,
|
||||
lineSpacingExtra,
|
||||
true);
|
||||
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
|
||||
// Is used for single-line, boring text when the width is either unknown or bigger
|
||||
|
@ -262,8 +264,8 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
textPaint,
|
||||
boring.width,
|
||||
Layout.Alignment.ALIGN_NORMAL,
|
||||
1.f,
|
||||
0.f,
|
||||
lineSpacingMultiplier,
|
||||
lineSpacingExtra,
|
||||
boring,
|
||||
true);
|
||||
} else {
|
||||
|
@ -273,8 +275,8 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
textPaint,
|
||||
(int) width,
|
||||
Layout.Alignment.ALIGN_NORMAL,
|
||||
1.f,
|
||||
0.f,
|
||||
lineSpacingMultiplier,
|
||||
lineSpacingExtra,
|
||||
true);
|
||||
}
|
||||
|
||||
|
@ -586,6 +588,7 @@ public class ReactTextShadowNode extends LayoutShadowNode {
|
|||
UNSET,
|
||||
mContainsImages,
|
||||
getPadding(),
|
||||
getEffectiveLineHeight(),
|
||||
getTextAlign()
|
||||
);
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
package com.facebook.react.views.text;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.view.Gravity;
|
||||
|
||||
import com.facebook.csslayout.Spacing;
|
||||
|
||||
|
@ -27,6 +28,7 @@ public class ReactTextUpdate {
|
|||
private final float mPaddingTop;
|
||||
private final float mPaddingRight;
|
||||
private final float mPaddingBottom;
|
||||
private final float mLineHeight;
|
||||
private final int mTextAlign;
|
||||
|
||||
public ReactTextUpdate(
|
||||
|
@ -34,6 +36,7 @@ public class ReactTextUpdate {
|
|||
int jsEventCounter,
|
||||
boolean containsImages,
|
||||
Spacing padding,
|
||||
float lineHeight,
|
||||
int textAlign) {
|
||||
mText = text;
|
||||
mJsEventCounter = jsEventCounter;
|
||||
|
@ -42,6 +45,7 @@ public class ReactTextUpdate {
|
|||
mPaddingTop = padding.get(Spacing.TOP);
|
||||
mPaddingRight = padding.get(Spacing.END);
|
||||
mPaddingBottom = padding.get(Spacing.BOTTOM);
|
||||
mLineHeight = lineHeight;
|
||||
mTextAlign = textAlign;
|
||||
}
|
||||
|
||||
|
@ -73,6 +77,10 @@ public class ReactTextUpdate {
|
|||
return mPaddingBottom;
|
||||
}
|
||||
|
||||
public float getLineHeight() {
|
||||
return mLineHeight;
|
||||
}
|
||||
|
||||
public int getTextAlign() {
|
||||
return mTextAlign;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import android.view.Gravity;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.csslayout.FloatUtil;
|
||||
import com.facebook.react.uimanager.ReactCompoundView;
|
||||
|
||||
public class ReactTextView extends TextView implements ReactCompoundView {
|
||||
|
@ -53,6 +54,16 @@ public class ReactTextView extends TextView implements ReactCompoundView {
|
|||
(int) Math.ceil(update.getPaddingRight()),
|
||||
(int) Math.ceil(update.getPaddingBottom()));
|
||||
|
||||
float nextLineHeight = update.getLineHeight();
|
||||
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
|
||||
mLineHeight = nextLineHeight;
|
||||
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
|
||||
setLineSpacing(0, 1);
|
||||
} else {
|
||||
setLineSpacing(mLineHeight, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int nextTextAlign = update.getTextAlign();
|
||||
if (mTextAlign != nextTextAlign) {
|
||||
mTextAlign = nextTextAlign;
|
||||
|
|
|
@ -129,6 +129,7 @@ public class ReactTextInputShadowNode extends ReactTextShadowNode implements
|
|||
mJsEventCount,
|
||||
mContainsImages,
|
||||
getPadding(),
|
||||
getEffectiveLineHeight(),
|
||||
mTextAlign
|
||||
);
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
|
||||
|
|
Loading…
Reference in New Issue