Android: Add support for having borders on <Text> & <TextInput> components

Summary:
Currently, `<Text>` and `<TextInput>` components on Android do not support borders.
This change adds support for the borderRadius, borderColor, and
borderWidth props on the `<Text>` and `<TextInput>` components on Android.

ReactViewGroup already implements this functionality so
we copied its implementation over into the ReactTextView
and ReactEditText classes.

**Test plan (required)**

Verified that the various border props work on Text and TextInput components in a test app.

Adam Comella
Microsoft Corp.
Closes https://github.com/facebook/react-native/pull/9658

Differential Revision: D3819993

Pulled By: lexs

fbshipit-source-id: 183b0aa95369dd781f03b5a1f0f409ab47284e39
This commit is contained in:
Adam Comella
2016-09-08 02:55:42 -07:00
committed by Facebook Github Bot 4
parent afde9da93d
commit 28ba749ba0
7 changed files with 216 additions and 2 deletions

View File

@@ -14,9 +14,11 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableStringBuilder;
@@ -39,6 +41,7 @@ import com.facebook.react.views.text.CustomStyleSpan;
import com.facebook.react.views.text.ReactTagSpan;
import com.facebook.react.views.text.ReactTextUpdate;
import com.facebook.react.views.text.TextInlineImageSpan;
import com.facebook.react.views.view.ReactViewBackgroundDrawable;
/**
* A wrapper around the EditText that lets us better control what happens when an EditText gets
@@ -76,6 +79,8 @@ public class ReactEditText extends EditText {
private final InternalKeyListener mKeyListener;
private boolean mDetectScrollMovement = false;
private ReactViewBackgroundDrawable mReactBackgroundDrawable;
private static final KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
public ReactEditText(Context context) {
@@ -478,6 +483,52 @@ public class ReactEditText extends EditText {
}
}
@Override
public void setBackgroundColor(int color) {
if (color == Color.TRANSPARENT && mReactBackgroundDrawable == null) {
// don't do anything, no need to allocate ReactBackgroundDrawable for transparent background
} else {
getOrCreateReactViewBackground().setColor(color);
}
}
public void setBorderWidth(int position, float width) {
getOrCreateReactViewBackground().setBorderWidth(position, width);
}
public void setBorderColor(int position, float color, float alpha) {
getOrCreateReactViewBackground().setBorderColor(position, color, alpha);
}
public void setBorderRadius(float borderRadius) {
getOrCreateReactViewBackground().setRadius(borderRadius);
}
public void setBorderRadius(float borderRadius, int position) {
getOrCreateReactViewBackground().setRadius(borderRadius, position);
}
public void setBorderStyle(@Nullable String style) {
getOrCreateReactViewBackground().setBorderStyle(style);
}
private ReactViewBackgroundDrawable getOrCreateReactViewBackground() {
if (mReactBackgroundDrawable == null) {
mReactBackgroundDrawable = new ReactViewBackgroundDrawable();
Drawable backgroundDrawable = getBackground();
super.setBackground(null); // required so that drawable callback is cleared before we add the
// drawable back as a part of LayerDrawable
if (backgroundDrawable == null) {
super.setBackground(mReactBackgroundDrawable);
} else {
LayerDrawable layerDrawable =
new LayerDrawable(new Drawable[]{mReactBackgroundDrawable, backgroundDrawable});
super.setBackground(layerDrawable);
}
}
return mReactBackgroundDrawable;
}
/**
* This class will redirect *TextChanged calls to the listeners only in the case where the text
* is changed by the user, and not explicitly set by JS.

View File

@@ -28,6 +28,8 @@ import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import com.facebook.csslayout.CSSConstants;
import com.facebook.csslayout.Spacing;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
@@ -42,10 +44,12 @@ import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewDefaults;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
import com.facebook.react.views.text.DefaultStyleValuesUtil;
import com.facebook.react.views.text.ReactTextUpdate;
import com.facebook.react.views.text.ReactTextView;
import com.facebook.react.views.text.TextInlineImageSpan;
/**
@@ -55,6 +59,10 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
/* package */ static final String REACT_CLASS = "AndroidTextInput";
private static final int[] SPACING_TYPES = {
Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM,
};
private static final int FOCUS_TEXT_INPUT = 1;
private static final int BLUR_TEXT_INPUT = 2;
@@ -497,6 +505,53 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
view.setImeActionLabel(returnKeyLabel, IME_ACTION_ID);
}
@ReactPropGroup(names = {
ViewProps.BORDER_RADIUS,
ViewProps.BORDER_TOP_LEFT_RADIUS,
ViewProps.BORDER_TOP_RIGHT_RADIUS,
ViewProps.BORDER_BOTTOM_RIGHT_RADIUS,
ViewProps.BORDER_BOTTOM_LEFT_RADIUS
}, defaultFloat = CSSConstants.UNDEFINED)
public void setBorderRadius(ReactEditText view, int index, float borderRadius) {
if (!CSSConstants.isUndefined(borderRadius)) {
borderRadius = PixelUtil.toPixelFromDIP(borderRadius);
}
if (index == 0) {
view.setBorderRadius(borderRadius);
} else {
view.setBorderRadius(borderRadius, index - 1);
}
}
@ReactProp(name = "borderStyle")
public void setBorderStyle(ReactEditText view, @Nullable String borderStyle) {
view.setBorderStyle(borderStyle);
}
@ReactPropGroup(names = {
ViewProps.BORDER_WIDTH,
ViewProps.BORDER_LEFT_WIDTH,
ViewProps.BORDER_RIGHT_WIDTH,
ViewProps.BORDER_TOP_WIDTH,
ViewProps.BORDER_BOTTOM_WIDTH,
}, defaultFloat = CSSConstants.UNDEFINED)
public void setBorderWidth(ReactEditText view, int index, float width) {
if (!CSSConstants.isUndefined(width)) {
width = PixelUtil.toPixelFromDIP(width);
}
view.setBorderWidth(SPACING_TYPES[index], width);
}
@ReactPropGroup(names = {
"borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor"
}, customType = "Color")
public void setBorderColor(ReactEditText view, int index, Integer color) {
float rgbComponent = color == null ? CSSConstants.UNDEFINED : (float) ((int)color & 0x00FFFFFF);
float alphaComponent = color == null ? CSSConstants.UNDEFINED : (float) ((int)color >>> 24);
view.setBorderColor(SPACING_TYPES[index], rgbComponent, alphaComponent);
}
@Override
protected void onAfterUpdateTransaction(ReactEditText view) {
super.onAfterUpdateTransaction(view);