Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions RNTester/js/TextExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,12 @@ class TextExample extends React.Component<{}> {
right right right right right right right right right right right
right right
</Text>
<Text style={{textAlign: 'justify'}}>
justify (works when api level >= 26 otherwise fallbacks to "left"):
this text component{"'"}s contents are laid out with "textAlign:
justify" and as you can see all of the lines except the last one
span the available width of the parent container.
</Text>
</RNTesterBlock>
<RNTesterBlock title="Unicode">
<View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ private static int parseNumericFontWeight(String fontWeightString) {
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;
Expand Down Expand Up @@ -377,19 +379,28 @@ public void setAllowFontScaling(boolean allowFontScaling) {

@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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,18 @@ public long measure(
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)) {
Expand Down Expand Up @@ -215,7 +219,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
getPadding(Spacing.END),
getPadding(Spacing.BOTTOM),
getTextAlign(),
mTextBreakStrategy);
mTextBreakStrategy,
mJustificationMode);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -49,7 +50,8 @@ public ReactTextUpdate(
paddingEnd,
paddingBottom,
textAlign,
Layout.BREAK_STRATEGY_HIGH_QUALITY);
Layout.BREAK_STRATEGY_HIGH_QUALITY,
Layout.JUSTIFICATION_MODE_NONE);
}

public ReactTextUpdate(
Expand All @@ -61,7 +63,8 @@ public ReactTextUpdate(
float paddingEnd,
float paddingBottom,
int textAlign,
int textBreakStrategy) {
int textBreakStrategy,
int justificationMode) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
Expand All @@ -71,6 +74,7 @@ public ReactTextUpdate(
mPaddingBottom = paddingBottom;
mTextAlign = textAlign;
mTextBreakStrategy = textBreakStrategy;
mJustificationMode = justificationMode;
}

public Spannable getText() {
Expand Down Expand Up @@ -108,4 +112,8 @@ public int getTextAlign() {
public int getTextBreakStrategy() {
return mTextBreakStrategy;
}

public int getJustificationMode() {
return mJustificationMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ public void setText(ReactTextUpdate update) {
setBreakStrategy(update.getTextBreakStrategy());
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (getJustificationMode() != update.getJustificationMode()) {
setJustificationMode(update.getJustificationMode());
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ public Object updateLocalData(ReactTextView view, ReactStylesDiffMap props, Reac
// 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,
Expand All @@ -92,7 +95,8 @@ public Object updateLocalData(ReactTextView view, ReactStylesDiffMap props, Reac
textViewProps.getEndPadding(),
textViewProps.getBottomPadding(),
textViewProps.getTextAlign(),
textBreakStrategy
textBreakStrategy,
justificationMode
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -204,19 +206,28 @@ public void setAllowFontScaling(boolean allowFontScaling) {
}

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);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
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;
Expand Down Expand Up @@ -430,19 +432,28 @@ public void setUnderlineColor(ReactEditText view, @Nullable Integer underlineCol

@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);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
getPadding(Spacing.RIGHT),
getPadding(Spacing.BOTTOM),
mTextAlign,
mTextBreakStrategy);
mTextBreakStrategy,
mJustificationMode);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
Expand Down Expand Up @@ -424,6 +425,21 @@ public void testMaxLinesApplied() {
assertThat(textView.getEllipsize()).isEqualTo(TextUtils.TruncateAt.END);
}

@TargetApi(Build.VERSION_CODES.O)
@Test
public void testTextAlignJustifyApplied() {
UIManagerModule uiManager = getUIManagerModule();

ReactRootView rootView = createText(
uiManager,
JavaOnlyMap.of("textAlign", "justify"),
JavaOnlyMap.of(ReactRawTextShadowNode.PROP_TEXT, "test text"));

TextView textView = (TextView) rootView.getChildAt(0);
assertThat(textView.getText().toString()).isEqualTo("test text");
assertThat(textView.getJustificationMode()).isEqualTo(Layout.JUSTIFICATION_MODE_INTER_WORD);
}

/**
* Make sure TextView has exactly one span and that span has given type.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Build;
import android.text.InputType;
import android.text.InputFilter;
import android.text.Layout;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.inputmethod.EditorInfo;
Expand Down Expand Up @@ -344,6 +346,10 @@ public void testTextAlign() {
assertThat(view.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK).isEqualTo(Gravity.CENTER_HORIZONTAL);
mManager.updateProperties(view, buildStyles("textAlign", null));
assertThat(view.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK).isEqualTo(defaultHorizontalGravity);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mManager.updateProperties(view, buildStyles("textAlign", "justify"));
assertThat(view.getJustificationMode()).isEqualTo(Layout.JUSTIFICATION_MODE_INTER_WORD);
}

// TextAlignVertical
mManager.updateProperties(view, buildStyles("textAlignVertical", "top"));
Expand Down