mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Text: Implement textAlign justify for android O+ (#22477)
Summary: Add textAlign justify for android O+(api level >=26) Resolves https://github.com/facebook/react-native/issues/22475 <img src="https://user-images.githubusercontent.com/615282/49341207-35e3b980-f685-11e8-91ab-dbc19c1ee4d0.gif" width="400" /> Changelog: ---------- [Android] [Added] - Implement textAlign justify for android O+ Pull Request resolved: https://github.com/facebook/react-native/pull/22477 Differential Revision: D13512004 Pulled By: cpojer fbshipit-source-id: e20f4976bfd957a5faeae0bbed2ff27c03023bb1
This commit is contained in:
committed by
Facebook Github Bot
parent
af52693e9c
commit
d2153fc58d
+23
-11
@@ -265,6 +265,9 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
protected int mTextAlign = Gravity.NO_GRAVITY;
|
||||
protected int mTextBreakStrategy =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
protected int mJustificationMode =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE;
|
||||
protected TextTransform mTextTransform = TextTransform.UNSET;
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
protected float mTextShadowOffsetDy = 0;
|
||||
@@ -357,19 +360,28 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
|
||||
@ReactProp(name = ViewProps.TEXT_ALIGN)
|
||||
public void setTextAlign(@Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else if ("justify".equals(textAlign)) {
|
||||
// Fallback gracefully for cross-platform compat instead of error
|
||||
if ("justify".equals(textAlign)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
|
||||
}
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
}
|
||||
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@@ -99,14 +99,18 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
|
||||
new StaticLayout(
|
||||
text, textPaint, hintWidth, alignment, 1.f, 0.f, mIncludeFontPadding);
|
||||
} else {
|
||||
layout =
|
||||
StaticLayout.Builder builder =
|
||||
StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
|
||||
.setAlignment(alignment)
|
||||
.setLineSpacing(0.f, 1.f)
|
||||
.setIncludePad(mIncludeFontPadding)
|
||||
.setBreakStrategy(mTextBreakStrategy)
|
||||
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
|
||||
.build();
|
||||
.setAlignment(alignment)
|
||||
.setLineSpacing(0.f, 1.f)
|
||||
.setIncludePad(mIncludeFontPadding)
|
||||
.setBreakStrategy(mTextBreakStrategy)
|
||||
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder.setJustificationMode(mJustificationMode);
|
||||
}
|
||||
layout = builder.build();
|
||||
}
|
||||
|
||||
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
|
||||
@@ -217,7 +221,8 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
|
||||
getPadding(Spacing.END),
|
||||
getPadding(Spacing.BOTTOM),
|
||||
getTextAlign(),
|
||||
mTextBreakStrategy);
|
||||
mTextBreakStrategy,
|
||||
mJustificationMode);
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class ReactTextUpdate {
|
||||
private final float mPaddingBottom;
|
||||
private final int mTextAlign;
|
||||
private final int mTextBreakStrategy;
|
||||
private final int mJustificationMode;
|
||||
|
||||
/**
|
||||
* @deprecated Use a non-deprecated constructor for ReactTextUpdate instead. This one remains
|
||||
@@ -49,7 +50,8 @@ public class ReactTextUpdate {
|
||||
paddingEnd,
|
||||
paddingBottom,
|
||||
textAlign,
|
||||
Layout.BREAK_STRATEGY_HIGH_QUALITY);
|
||||
Layout.BREAK_STRATEGY_HIGH_QUALITY,
|
||||
Layout.JUSTIFICATION_MODE_NONE);
|
||||
}
|
||||
|
||||
public ReactTextUpdate(
|
||||
@@ -61,7 +63,8 @@ public class ReactTextUpdate {
|
||||
float paddingEnd,
|
||||
float paddingBottom,
|
||||
int textAlign,
|
||||
int textBreakStrategy) {
|
||||
int textBreakStrategy,
|
||||
int justificationMode) {
|
||||
mText = text;
|
||||
mJsEventCounter = jsEventCounter;
|
||||
mContainsImages = containsImages;
|
||||
@@ -71,6 +74,7 @@ public class ReactTextUpdate {
|
||||
mPaddingBottom = paddingBottom;
|
||||
mTextAlign = textAlign;
|
||||
mTextBreakStrategy = textBreakStrategy;
|
||||
mJustificationMode = justificationMode;
|
||||
}
|
||||
|
||||
public Spannable getText() {
|
||||
@@ -108,4 +112,8 @@ public class ReactTextUpdate {
|
||||
public int getTextBreakStrategy() {
|
||||
return mTextBreakStrategy;
|
||||
}
|
||||
|
||||
public int getJustificationMode() {
|
||||
return mJustificationMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,11 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
||||
setBreakStrategy(update.getTextBreakStrategy());
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (getJustificationMode() != update.getJustificationMode()) {
|
||||
setJustificationMode(update.getJustificationMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,6 +79,9 @@ public class ReactTextViewManager
|
||||
// TODO add textBreakStrategy prop into local Data
|
||||
int textBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
|
||||
// TODO add justificationMode prop into local Data
|
||||
int justificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
|
||||
return new ReactTextUpdate(
|
||||
spanned,
|
||||
-1, // TODO add this into local Data?
|
||||
@@ -88,7 +91,9 @@ public class ReactTextViewManager
|
||||
textViewProps.getEndPadding(),
|
||||
textViewProps.getBottomPadding(),
|
||||
textViewProps.getTextAlign(),
|
||||
textBreakStrategy);
|
||||
textBreakStrategy,
|
||||
justificationMode
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,6 +50,8 @@ public class TextAttributeProps {
|
||||
protected int mTextAlign = Gravity.NO_GRAVITY;
|
||||
protected int mTextBreakStrategy =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
protected int mJustificationMode =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE;
|
||||
protected TextTransform mTextTransform = TextTransform.UNSET;
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
@@ -204,19 +206,28 @@ public class TextAttributeProps {
|
||||
}
|
||||
|
||||
public void setTextAlign(@Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else if ("justify".equals(textAlign)) {
|
||||
// Fallback gracefully for cross-platform compat instead of error
|
||||
if ("justify".equals(textAlign)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
|
||||
}
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
}
|
||||
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-11
@@ -15,6 +15,7 @@ import android.support.v4.content.ContextCompat;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.Layout;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.TypedValue;
|
||||
@@ -460,19 +461,28 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
|
||||
|
||||
@ReactProp(name = ViewProps.TEXT_ALIGN)
|
||||
public void setTextAlign(ReactEditText view, @Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.NO_GRAVITY);
|
||||
} else if ("left".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.LEFT);
|
||||
} else if ("right".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.RIGHT);
|
||||
} else if ("center".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
|
||||
} else if ("justify".equals(textAlign)) {
|
||||
// Fallback gracefully for cross-platform compat instead of error
|
||||
if ("justify".equals(textAlign)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
view.setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD);
|
||||
}
|
||||
view.setGravityHorizontal(Gravity.LEFT);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
view.setJustificationMode(Layout.JUSTIFICATION_MODE_NONE);
|
||||
}
|
||||
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.NO_GRAVITY);
|
||||
} else if ("left".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.LEFT);
|
||||
} else if ("right".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.RIGHT);
|
||||
} else if ("center".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -204,7 +204,8 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
|
||||
getPadding(Spacing.RIGHT),
|
||||
getPadding(Spacing.BOTTOM),
|
||||
mTextAlign,
|
||||
mTextBreakStrategy);
|
||||
mTextBreakStrategy,
|
||||
mJustificationMode);
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user