Added support for corner radii in Android

Summary:
This is a cut down version of a previous pull request with just the 4 corners catered for.
Closes https://github.com/facebook/react-native/pull/4252

Reviewed By: svcscm

Differential Revision: D2911959

Pulled By: androidtrunkagent

fb-gh-sync-id: 7ddcd684d90d4d92ccefed906c0126e92818dcde
This commit is contained in:
mattds 2016-02-08 10:42:31 -08:00 committed by facebook-github-bot-7
parent 17fcc9440f
commit 4937a4c5cd
5 changed files with 124 additions and 12 deletions

View File

@ -98,6 +98,20 @@ var styles = StyleSheet.create({
marginRight: 10, marginRight: 10,
backgroundColor: 'lightgrey', backgroundColor: 'lightgrey',
}, },
border9: {
borderWidth: 10,
borderTopLeftRadius: 10,
borderBottomRightRadius: 20,
borderColor: 'black',
},
border10: {
borderWidth: 10,
backgroundColor: 'white',
borderTopLeftRadius: 10,
borderBottomRightRadius: 20,
borderColor: 'black',
elevation: 10
}
}); });
exports.title = 'Border'; exports.title = 'Border';
@ -180,4 +194,19 @@ exports.examples = [
); );
} }
}, },
{
title: 'Corner Radii',
description: 'borderTopLeftRadius & borderBottomRightRadius',
render() {
return <View style={[styles.box, styles.border9]} />;
}
},
{
title: 'Corner Radii / Elevation',
description: 'borderTopLeftRadius & borderBottomRightRadius & elevation',
platform: 'android',
render() {
return <View style={[styles.box, styles.border10]} />;
}
},
]; ];

View File

@ -77,6 +77,11 @@ public class ViewProps {
public static final String BORDER_TOP_WIDTH = "borderTopWidth"; public static final String BORDER_TOP_WIDTH = "borderTopWidth";
public static final String BORDER_RIGHT_WIDTH = "borderRightWidth"; public static final String BORDER_RIGHT_WIDTH = "borderRightWidth";
public static final String BORDER_BOTTOM_WIDTH = "borderBottomWidth"; public static final String BORDER_BOTTOM_WIDTH = "borderBottomWidth";
public static final String BORDER_RADIUS = "borderRadius";
public static final String BORDER_TOP_LEFT_RADIUS = "borderTopLeftRadius";
public static final String BORDER_TOP_RIGHT_RADIUS = "borderTopRightRadius";
public static final String BORDER_BOTTOM_LEFT_RADIUS = "borderBottomLeftRadius";
public static final String BORDER_BOTTOM_RIGHT_RADIUS = "borderBottomRightRadius";
public static final int[] BORDER_SPACING_TYPES = { public static final int[] BORDER_SPACING_TYPES = {
Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM
}; };

View File

@ -11,6 +11,7 @@ package com.facebook.react.views.view;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import android.graphics.Canvas; import android.graphics.Canvas;
@ -78,7 +79,9 @@ import com.facebook.csslayout.Spacing;
/* Used for rounded border and rounded background */ /* Used for rounded border and rounded background */
private @Nullable PathEffect mPathEffectForBorderStyle; private @Nullable PathEffect mPathEffectForBorderStyle;
private @Nullable Path mPathForBorderRadius; private @Nullable Path mPathForBorderRadius;
private @Nullable Path mPathForBorderRadiusOutline;
private @Nullable RectF mTempRectForBorderRadius; private @Nullable RectF mTempRectForBorderRadius;
private @Nullable RectF mTempRectForBorderRadiusOutline;
private boolean mNeedUpdatePathForBorderRadius = false; private boolean mNeedUpdatePathForBorderRadius = false;
private float mBorderRadius = CSSConstants.UNDEFINED; private float mBorderRadius = CSSConstants.UNDEFINED;
@ -87,9 +90,11 @@ import com.facebook.csslayout.Spacing;
private int mColor = Color.TRANSPARENT; private int mColor = Color.TRANSPARENT;
private int mAlpha = 255; private int mAlpha = 255;
private @Nullable float[] mBorderCornerRadii;
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
if (!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) { if ((!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) || mBorderCornerRadii != null) {
drawRoundedBackgroundWithBorders(canvas); drawRoundedBackgroundWithBorders(canvas);
} else { } else {
drawRectangularBackgroundWithBorders(canvas); drawRectangularBackgroundWithBorders(canvas);
@ -132,11 +137,10 @@ import com.facebook.csslayout.Spacing;
super.getOutline(outline); super.getOutline(outline);
return; return;
} }
if(!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) { if((!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) || mBorderCornerRadii != null) {
float extraRadiusFromBorderWidth = (mBorderWidth != null) updatePath();
? mBorderWidth.get(Spacing.ALL) / 2f
: 0; outline.setConvexPath(mPathForBorderRadiusOutline);
outline.setRoundRect(getBounds(), mBorderRadius + extraRadiusFromBorderWidth);
} else { } else {
outline.setRect(getBounds()); outline.setRect(getBounds());
} }
@ -181,8 +185,22 @@ import com.facebook.csslayout.Spacing;
} }
public void setRadius(float radius) { public void setRadius(float radius) {
if (mBorderRadius != radius) { if (!FloatUtil.floatsEqual(mBorderRadius,radius)) {
mBorderRadius = radius; mBorderRadius = radius;
mNeedUpdatePathForBorderRadius = true;
invalidateSelf();
}
}
public void setRadius(float radius, int position) {
if (mBorderCornerRadii == null) {
mBorderCornerRadii = new float[4];
Arrays.fill(mBorderCornerRadii, CSSConstants.UNDEFINED);
}
if (!FloatUtil.floatsEqual(mBorderCornerRadii[position], radius)) {
mBorderCornerRadii[position] = radius;
mNeedUpdatePathForBorderRadius = true;
invalidateSelf(); invalidateSelf();
} }
} }
@ -225,19 +243,61 @@ import com.facebook.csslayout.Spacing;
if (mPathForBorderRadius == null) { if (mPathForBorderRadius == null) {
mPathForBorderRadius = new Path(); mPathForBorderRadius = new Path();
mTempRectForBorderRadius = new RectF(); mTempRectForBorderRadius = new RectF();
mPathForBorderRadiusOutline = new Path();
mTempRectForBorderRadiusOutline = new RectF();
} }
mPathForBorderRadius.reset(); mPathForBorderRadius.reset();
mPathForBorderRadiusOutline.reset();
mTempRectForBorderRadius.set(getBounds()); mTempRectForBorderRadius.set(getBounds());
mTempRectForBorderRadiusOutline.set(getBounds());
float fullBorderWidth = getFullBorderWidth(); float fullBorderWidth = getFullBorderWidth();
if (fullBorderWidth > 0) { if (fullBorderWidth > 0) {
mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f); mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f);
} }
float defaultBorderRadius = !CSSConstants.isUndefined(mBorderRadius) ? mBorderRadius : 0;
float topLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[0]) ? mBorderCornerRadii[0] : defaultBorderRadius;
float topRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[1]) ? mBorderCornerRadii[1] : defaultBorderRadius;
float bottomRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius;
float bottomLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius;
mPathForBorderRadius.addRoundRect( mPathForBorderRadius.addRoundRect(
mTempRectForBorderRadius, mTempRectForBorderRadius,
mBorderRadius, new float[] {
mBorderRadius, topLeftRadius,
topLeftRadius,
topRightRadius,
topRightRadius,
bottomRightRadius,
bottomRightRadius,
bottomLeftRadius,
bottomLeftRadius
},
Path.Direction.CW); Path.Direction.CW);
float extraRadiusForOutline = 0;
if (mBorderWidth != null) {
extraRadiusForOutline = mBorderWidth.get(Spacing.ALL) / 2f;
}
mPathForBorderRadiusOutline.addRoundRect(
mTempRectForBorderRadiusOutline,
new float[] {
topLeftRadius + extraRadiusForOutline,
topLeftRadius + extraRadiusForOutline,
topRightRadius + extraRadiusForOutline,
topRightRadius + extraRadiusForOutline,
bottomRightRadius + extraRadiusForOutline,
bottomRightRadius + extraRadiusForOutline,
bottomLeftRadius + extraRadiusForOutline,
bottomLeftRadius + extraRadiusForOutline
},
Path.Direction.CW);
mPathEffectForBorderStyle = mBorderStyle != null mPathEffectForBorderStyle = mBorderStyle != null
? mBorderStyle.getPathEffect(getFullBorderWidth()) ? mBorderStyle.getPathEffect(getFullBorderWidth())
: null; : null;

View File

@ -207,6 +207,10 @@ public class ReactViewGroup extends ViewGroup implements
getOrCreateReactViewBackground().setRadius(borderRadius); getOrCreateReactViewBackground().setRadius(borderRadius);
} }
public void setBorderRadius(float borderRadius, int position) {
getOrCreateReactViewBackground().setRadius(borderRadius, position);
}
public void setBorderStyle(@Nullable String style) { public void setBorderStyle(@Nullable String style) {
getOrCreateReactViewBackground().setBorderStyle(style); getOrCreateReactViewBackground().setBorderStyle(style);
} }

View File

@ -51,9 +51,23 @@ public class ReactViewManager extends ViewGroupManager<ReactViewGroup> {
view.setFocusable(accessible); view.setFocusable(accessible);
} }
@ReactProp(name = "borderRadius") @ReactPropGroup(names = {
public void setBorderRadius(ReactViewGroup view, float borderRadius) { ViewProps.BORDER_RADIUS,
view.setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius)); 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(ReactViewGroup 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") @ReactProp(name = "borderStyle")