Implement border(Left|Right|Top|Bottom)Color for rounded borders
Reviewed By: achen1 Differential Revision: D6009609 fbshipit-source-id: 6a247a14aa48ac2edc637bf064216407a3a9a81f
This commit is contained in:
parent
4994d6a389
commit
f7888310d4
|
@ -124,6 +124,44 @@ var styles = StyleSheet.create({
|
|||
borderBottomColor: 'transparent',
|
||||
borderLeftColor: 'red',
|
||||
},
|
||||
border12: {
|
||||
borderStyle: 'solid',
|
||||
overflow: 'hidden',
|
||||
borderTopWidth: 10,
|
||||
borderRightWidth: 20,
|
||||
borderBottomWidth: 30,
|
||||
borderLeftWidth: 40,
|
||||
borderRadius: 20,
|
||||
},
|
||||
border13: {
|
||||
borderStyle: 'solid',
|
||||
overflow: 'hidden',
|
||||
borderTopWidth: 10,
|
||||
borderRightWidth: 20,
|
||||
borderBottomWidth: 30,
|
||||
borderLeftWidth: 40,
|
||||
borderTopColor: 'red',
|
||||
borderRightColor: 'green',
|
||||
borderBottomColor: 'blue',
|
||||
borderLeftColor: 'magenta',
|
||||
borderRadius: 20,
|
||||
},
|
||||
border14: {
|
||||
borderStyle: 'solid',
|
||||
overflow: 'hidden',
|
||||
borderTopWidth: 10,
|
||||
borderRightWidth: 20,
|
||||
borderBottomWidth: 30,
|
||||
borderLeftWidth: 40,
|
||||
borderTopColor: 'red',
|
||||
borderRightColor: 'green',
|
||||
borderBottomColor: 'blue',
|
||||
borderLeftColor: 'magenta',
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 40,
|
||||
borderBottomRightRadius: 30,
|
||||
borderBottomLeftRadius: 40,
|
||||
}
|
||||
});
|
||||
|
||||
exports.title = 'Border';
|
||||
|
@ -228,4 +266,25 @@ exports.examples = [
|
|||
return <View style={[styles.border11]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Curved border(Left|Right|Bottom|Top)Width',
|
||||
description: 'Make a non-uniform width curved border',
|
||||
render() {
|
||||
return <View style={[styles.box, styles.border12]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Curved border(Left|Right|Bottom|Top)Color',
|
||||
description: 'Make a non-uniform color curved border',
|
||||
render() {
|
||||
return <View style={[styles.box, styles.border13]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Curved border(Top|Bottom)(Left|Right)Radius',
|
||||
description: 'Make a non-uniform radius curved border',
|
||||
render() {
|
||||
return <View style={[styles.box, styles.border14]} />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
|
@ -17,6 +17,7 @@ import android.graphics.Outline;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PathEffect;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
|
@ -91,6 +92,10 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
private @Nullable RectF mInnerClipTempRectForBorderRadius;
|
||||
private @Nullable RectF mOuterClipTempRectForBorderRadius;
|
||||
private @Nullable RectF mTempRectForBorderRadiusOutline;
|
||||
private @Nullable PointF mInnerTopLeftCorner;
|
||||
private @Nullable PointF mInnerTopRightCorner;
|
||||
private @Nullable PointF mInnerBottomRightCorner;
|
||||
private @Nullable PointF mInnerBottomLeftCorner;
|
||||
private boolean mNeedUpdatePathForBorderRadius = false;
|
||||
private float mBorderRadius = YogaConstants.UNDEFINED;
|
||||
|
||||
|
@ -293,14 +298,73 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
|| borderBottomWidth > 0
|
||||
|| borderLeftWidth > 0
|
||||
|| borderRightWidth > 0) {
|
||||
int borderColor = getFullBorderColor();
|
||||
mPaint.setColor(ColorUtil.multiplyColorAlpha(borderColor, mAlpha));
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
// Draw border
|
||||
canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT);
|
||||
canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE);
|
||||
canvas.drawRect(getBounds(), mPaint);
|
||||
|
||||
final int colorLeft = getBorderColor(Spacing.LEFT);
|
||||
final int colorTop = getBorderColor(Spacing.TOP);
|
||||
final int colorRight = getBorderColor(Spacing.RIGHT);
|
||||
final int colorBottom = getBorderColor(Spacing.BOTTOM);
|
||||
|
||||
final float left = mOuterClipTempRectForBorderRadius.left;
|
||||
final float right = mOuterClipTempRectForBorderRadius.right;
|
||||
final float top = mOuterClipTempRectForBorderRadius.top;
|
||||
final float bottom = mOuterClipTempRectForBorderRadius.bottom;
|
||||
|
||||
if (borderLeftWidth > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = top;
|
||||
final float x2 = mInnerTopLeftCorner.x;
|
||||
final float y2 = mInnerTopLeftCorner.y;
|
||||
final float x3 = mInnerBottomLeftCorner.x;
|
||||
final float y3 = mInnerBottomLeftCorner.y;
|
||||
final float x4 = left;
|
||||
final float y4 = bottom;
|
||||
|
||||
drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderTopWidth > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = top;
|
||||
final float x2 = mInnerTopLeftCorner.x;
|
||||
final float y2 = mInnerTopLeftCorner.y;
|
||||
final float x3 = mInnerTopRightCorner.x;
|
||||
final float y3 = mInnerTopRightCorner.y;
|
||||
final float x4 = right;
|
||||
final float y4 = top;
|
||||
|
||||
drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderRightWidth > 0) {
|
||||
final float x1 = right;
|
||||
final float y1 = top;
|
||||
final float x2 = mInnerTopRightCorner.x;
|
||||
final float y2 = mInnerTopRightCorner.y;
|
||||
final float x3 = mInnerBottomRightCorner.x;
|
||||
final float y3 = mInnerBottomRightCorner.y;
|
||||
final float x4 = right;
|
||||
final float y4 = bottom;
|
||||
|
||||
drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderBottomWidth > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = bottom;
|
||||
final float x2 = mInnerBottomLeftCorner.x;
|
||||
final float y2 = mInnerBottomLeftCorner.y;
|
||||
final float x3 = mInnerBottomRightCorner.x;
|
||||
final float y3 = mInnerBottomRightCorner.y;
|
||||
final float x4 = right;
|
||||
final float y4 = bottom;
|
||||
|
||||
drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.restore();
|
||||
|
@ -366,17 +430,27 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
final float bottomRightRadius =
|
||||
getBorderRadiusOrDefaultTo(borderRadius, BorderRadiusLocation.BOTTOM_RIGHT);
|
||||
|
||||
|
||||
final float innerTopLeftRadiusX = Math.max(topLeftRadius - borderLeftWidth, 0);
|
||||
final float innerTopLeftRadiusY = Math.max(topLeftRadius - borderTopWidth, 0);
|
||||
final float innerTopRightRadiusX = Math.max(topRightRadius - borderRightWidth, 0);
|
||||
final float innerTopRightRadiusY = Math.max(topRightRadius - borderTopWidth, 0);
|
||||
final float innerBottomRightRadiusX = Math.max(bottomRightRadius - borderRightWidth, 0);
|
||||
final float innerBottomRightRadiusY = Math.max(bottomRightRadius - borderBottomWidth, 0);
|
||||
final float innerBottomLeftRadiusX = Math.max(bottomLeftRadius - borderLeftWidth, 0);
|
||||
final float innerBottomLeftRadiusY = Math.max(bottomLeftRadius - borderBottomWidth, 0);
|
||||
|
||||
mInnerClipPathForBorderRadius.addRoundRect(
|
||||
mInnerClipTempRectForBorderRadius,
|
||||
new float[] {
|
||||
Math.max(topLeftRadius - borderLeftWidth, 0),
|
||||
Math.max(topLeftRadius - borderTopWidth, 0),
|
||||
Math.max(topRightRadius - borderRightWidth, 0),
|
||||
Math.max(topRightRadius - borderTopWidth, 0),
|
||||
Math.max(bottomRightRadius - borderRightWidth, 0),
|
||||
Math.max(bottomRightRadius - borderBottomWidth, 0),
|
||||
Math.max(bottomLeftRadius - borderLeftWidth, 0),
|
||||
Math.max(bottomLeftRadius - borderBottomWidth, 0),
|
||||
innerTopLeftRadiusX,
|
||||
innerTopLeftRadiusY,
|
||||
innerTopRightRadiusX,
|
||||
innerTopRightRadiusY,
|
||||
innerBottomRightRadiusX,
|
||||
innerBottomRightRadiusY,
|
||||
innerBottomLeftRadiusX,
|
||||
innerBottomLeftRadiusY,
|
||||
},
|
||||
Path.Direction.CW);
|
||||
|
||||
|
@ -414,6 +488,259 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
bottomLeftRadius + extraRadiusForOutline
|
||||
},
|
||||
Path.Direction.CW);
|
||||
|
||||
/**
|
||||
* Rounded Multi-Colored Border Algorithm:
|
||||
*
|
||||
* <p>Let O (for outer) = (top, left, bottom, right) be the rectangle that represents the size
|
||||
* and position of a view V. Since the box-sizing of all React Native views is border-box, any
|
||||
* border of V will render inside O.
|
||||
*
|
||||
* <p>Let BorderWidth = (borderTop, borderLeft, borderBottom, borderRight).
|
||||
* <p>Let I (for inner) = O - BorderWidth.
|
||||
*
|
||||
* <p>Then, remembering that O and I are rectangles and that I is inside O, O - I gives us the
|
||||
* border of V. Therefore, we can use canvas.clipPath to draw V's border.
|
||||
*
|
||||
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
||||
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
||||
* <p>canvas.drawRect(O, paint);
|
||||
*
|
||||
* <p>This lets us draw non-rounded single-color borders.
|
||||
*
|
||||
* <p>To extend this algorithm to rounded single-color borders, we:
|
||||
* <p>1. Curve the corners of O by the (border radii of V) using Path#addRoundRect.
|
||||
* <p>2. Curve the corners of I by (border radii of V - border widths of V) using
|
||||
* Path#addRoundRect.
|
||||
*
|
||||
* <p>Let O' = curve(O, border radii of V).
|
||||
* <p>Let I' = curve(I, border radii of V - border widths of V)
|
||||
*
|
||||
* <p>The rationale behind this decision is the (first sentence of the) following section in the
|
||||
* CSS Backgrounds and Borders Module Level 3:
|
||||
* https://www.w3.org/TR/css3-background/#the-border-radius.
|
||||
*
|
||||
* <p>After both O and I have been curved, we can execute the following lines once again to
|
||||
* render curved single-color borders:
|
||||
*
|
||||
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
||||
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
||||
* <p>canvas.drawRect(O, paint);
|
||||
*
|
||||
* <p>To extend this algorithm to rendering multi-colored rounded borders, we render each side
|
||||
* of the border as its own quadrilateral. Suppose that we were handling the case where all the
|
||||
* border radii are 0. Then, the four quadrilaterals would be:
|
||||
*
|
||||
* <p>Left: (O.left, O.top), (I.left, I.top), (I.left, I.bottom), (O.left, O.bottom)
|
||||
* <p>Top: (O.left, O.top), (I.left, I.top), (I.right, I.top), (O.right, O.top)
|
||||
* <p>Right: (O.right, O.top), (I.right, I.top), (I.right, I.bottom), (O.right, O.bottom)
|
||||
* <p>Bottom: (O.right, O.bottom), (I.right, I.bottom), (I.left, I.bottom), (O.left, O.bottom)
|
||||
*
|
||||
* <p>Now, lets consider what happens when we render a rounded border (radii != 0). For the sake
|
||||
* of simplicity, let's focus on the top edge of the Left border:
|
||||
*
|
||||
* <p>Let borderTopLeftRadius = 5. Let borderLeftWidth = 1. Let borderTopWidth = 2.
|
||||
*
|
||||
* <p>We know that O is curved by the ellipse E_O (a = 5, b = 5). We know that I is curved by
|
||||
* the ellipse E_I (a = 5 - 1, b = 5 - 2).
|
||||
*
|
||||
* <p>Since we have clipping, it should be safe to set the top-left point of the Left
|
||||
* quadrilateral's top edge to (O.left, O.top).
|
||||
*
|
||||
* <p>But, what should the top-right point be?
|
||||
*
|
||||
* <p>The fact that the border is curved shouldn't change the slope (nor the position) of the
|
||||
* line connecting the top-left and top-right points of the Left quadrilateral's top edge.
|
||||
* Therefore, The top-right point should lie somewhere on the line L = (1 - a) * (O.left, O.top)
|
||||
* + a * (I.left, I.top).
|
||||
*
|
||||
* <p>a != 0, because then the top-left and top-right points would be the same and
|
||||
* borderLeftWidth = 1. a != 1, because then the top-right point would not touch an edge of the
|
||||
* ellipse E_I. We want the top-right point to touch an edge of the inner ellipse because the
|
||||
* border curves with E_I on the top-left corner of V.
|
||||
*
|
||||
* <p>Therefore, it must be the case that a > 1. Two natural locations of the top-right point
|
||||
* exist: 1. The first intersection of L with E_I. 2. The second intersection of L with E_I.
|
||||
*
|
||||
* <p>We choose the top-right point of the top edge of the Left quadrilateral to be an arbitrary
|
||||
* intersection of L with E_I.
|
||||
*/
|
||||
if (mInnerTopLeftCorner == null) {
|
||||
mInnerTopLeftCorner = new PointF();
|
||||
}
|
||||
|
||||
/** Compute mInnerTopLeftCorner */
|
||||
mInnerTopLeftCorner.x = mInnerClipTempRectForBorderRadius.left;
|
||||
mInnerTopLeftCorner.y = mInnerClipTempRectForBorderRadius.top;
|
||||
|
||||
getEllipseIntersectionWithLine(
|
||||
// Ellipse Bounds
|
||||
mInnerClipTempRectForBorderRadius.left,
|
||||
mInnerClipTempRectForBorderRadius.top,
|
||||
mInnerClipTempRectForBorderRadius.left + 2 * innerTopLeftRadiusX,
|
||||
mInnerClipTempRectForBorderRadius.top + 2 * innerTopLeftRadiusY,
|
||||
|
||||
// Line Start
|
||||
mOuterClipTempRectForBorderRadius.left,
|
||||
mOuterClipTempRectForBorderRadius.top,
|
||||
|
||||
// Line End
|
||||
mInnerClipTempRectForBorderRadius.left,
|
||||
mInnerClipTempRectForBorderRadius.top,
|
||||
|
||||
// Result
|
||||
mInnerTopLeftCorner);
|
||||
|
||||
/** Compute mInnerBottomLeftCorner */
|
||||
if (mInnerBottomLeftCorner == null) {
|
||||
mInnerBottomLeftCorner = new PointF();
|
||||
}
|
||||
|
||||
mInnerBottomLeftCorner.x = mInnerClipTempRectForBorderRadius.left;
|
||||
mInnerBottomLeftCorner.y = mInnerClipTempRectForBorderRadius.bottom;
|
||||
|
||||
getEllipseIntersectionWithLine(
|
||||
// Ellipse Bounds
|
||||
mInnerClipTempRectForBorderRadius.left,
|
||||
mInnerClipTempRectForBorderRadius.bottom - 2 * innerBottomLeftRadiusY,
|
||||
mInnerClipTempRectForBorderRadius.left + 2 * innerBottomLeftRadiusX,
|
||||
mInnerClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Line Start
|
||||
mOuterClipTempRectForBorderRadius.left,
|
||||
mOuterClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Line End
|
||||
mInnerClipTempRectForBorderRadius.left,
|
||||
mInnerClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Result
|
||||
mInnerBottomLeftCorner);
|
||||
|
||||
/** Compute mInnerTopRightCorner */
|
||||
if (mInnerTopRightCorner == null) {
|
||||
mInnerTopRightCorner = new PointF();
|
||||
}
|
||||
|
||||
mInnerTopRightCorner.x = mInnerClipTempRectForBorderRadius.right;
|
||||
mInnerTopRightCorner.y = mInnerClipTempRectForBorderRadius.top;
|
||||
|
||||
getEllipseIntersectionWithLine(
|
||||
// Ellipse Bounds
|
||||
mInnerClipTempRectForBorderRadius.right - 2 * innerTopRightRadiusX,
|
||||
mInnerClipTempRectForBorderRadius.top,
|
||||
mInnerClipTempRectForBorderRadius.right,
|
||||
mInnerClipTempRectForBorderRadius.top + 2 * innerTopRightRadiusY,
|
||||
|
||||
// Line Start
|
||||
mOuterClipTempRectForBorderRadius.right,
|
||||
mOuterClipTempRectForBorderRadius.top,
|
||||
|
||||
// Line End
|
||||
mInnerClipTempRectForBorderRadius.right,
|
||||
mInnerClipTempRectForBorderRadius.top,
|
||||
|
||||
// Result
|
||||
mInnerTopRightCorner);
|
||||
|
||||
/** Compute mInnerBottomRightCorner */
|
||||
if (mInnerBottomRightCorner == null) {
|
||||
mInnerBottomRightCorner = new PointF();
|
||||
}
|
||||
|
||||
mInnerBottomRightCorner.x = mInnerClipTempRectForBorderRadius.right;
|
||||
mInnerBottomRightCorner.y = mInnerClipTempRectForBorderRadius.bottom;
|
||||
|
||||
getEllipseIntersectionWithLine(
|
||||
// Ellipse Bounds
|
||||
mInnerClipTempRectForBorderRadius.right - 2 * innerBottomRightRadiusX,
|
||||
mInnerClipTempRectForBorderRadius.bottom - 2 * innerBottomRightRadiusY,
|
||||
mInnerClipTempRectForBorderRadius.right,
|
||||
mInnerClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Line Start
|
||||
mOuterClipTempRectForBorderRadius.right,
|
||||
mOuterClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Line End
|
||||
mInnerClipTempRectForBorderRadius.right,
|
||||
mInnerClipTempRectForBorderRadius.bottom,
|
||||
|
||||
// Result
|
||||
mInnerBottomRightCorner);
|
||||
}
|
||||
|
||||
private static void getEllipseIntersectionWithLine(
|
||||
double ellipseBoundsLeft,
|
||||
double ellipseBoundsTop,
|
||||
double ellipseBoundsRight,
|
||||
double ellipseBoundsBottom,
|
||||
double lineStartX,
|
||||
double lineStartY,
|
||||
double lineEndX,
|
||||
double lineEndY,
|
||||
PointF result) {
|
||||
final double ellipseCenterX = (ellipseBoundsLeft + ellipseBoundsRight) / 2;
|
||||
final double ellipseCenterY = (ellipseBoundsTop + ellipseBoundsBottom) / 2;
|
||||
|
||||
/**
|
||||
* Step 1:
|
||||
*
|
||||
* Translate the line so that the ellipse is at the origin.
|
||||
*
|
||||
* Why? It makes the math easier by changing the ellipse equation from
|
||||
* ((x - ellipseCenterX)/a)^2 + ((y - ellipseCenterY)/b)^2 = 1 to
|
||||
* (x/a)^2 + (y/b)^2 = 1.
|
||||
*/
|
||||
lineStartX -= ellipseCenterX;
|
||||
lineStartY -= ellipseCenterY;
|
||||
lineEndX -= ellipseCenterX;
|
||||
lineEndY -= ellipseCenterY;
|
||||
|
||||
/**
|
||||
* Step 2:
|
||||
*
|
||||
* Ellipse equation: (x/a)^2 + (y/b)^2 = 1
|
||||
* Line equation: y = mx + c
|
||||
*/
|
||||
final double a = Math.abs(ellipseBoundsRight - ellipseBoundsLeft) / 2;
|
||||
final double b = Math.abs(ellipseBoundsBottom - ellipseBoundsTop) / 2;
|
||||
final double m = (lineEndY - lineStartY) / (lineEndX - lineStartX);
|
||||
final double c = lineStartY - m * lineStartX; // Just a point on the line
|
||||
|
||||
/**
|
||||
* Step 3:
|
||||
*
|
||||
* Substitute the Line equation into the Ellipse equation. Solve for x.
|
||||
* Eventually, you'll have to use the quadratic formula.
|
||||
*
|
||||
* Quadratic formula: Ax^2 + Bx + C = 0
|
||||
*/
|
||||
final double A = (b * b + a * a * m * m);
|
||||
final double B = 2 * a * a * c * m;
|
||||
final double C = (a * a * (c * c - b * b));
|
||||
|
||||
/**
|
||||
* Step 4:
|
||||
*
|
||||
* Apply Quadratic formula. D = determinant / 2A
|
||||
*/
|
||||
final double D = Math.sqrt(-C / A + Math.pow(B / (2 * A), 2));
|
||||
final double x2 = -B / (2 * A) - D;
|
||||
final double y2 = m * x2 + c;
|
||||
|
||||
/**
|
||||
* Step 5:
|
||||
*
|
||||
* Undo the space transformation in Step 5.
|
||||
*/
|
||||
final double x = x2 + ellipseCenterX;
|
||||
final double y = y2 + ellipseCenterY;
|
||||
|
||||
if (!Double.isNaN(x) && !Double.isNaN(y)) {
|
||||
result.x = (float) x;
|
||||
result.y = (float) y;
|
||||
}
|
||||
}
|
||||
|
||||
public float getBorderWidthOrDefaultTo(final float defaultValue, final int spacingType) {
|
||||
|
@ -447,18 +774,6 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
mBorderWidth.getRaw(Spacing.ALL) : 0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* We use this method for getting color for rounded borders only similarly as for
|
||||
* {@link #getFullBorderWidth}.
|
||||
*/
|
||||
private int getFullBorderColor() {
|
||||
float rgb = (mBorderRGB != null && !YogaConstants.isUndefined(mBorderRGB.getRaw(Spacing.ALL))) ?
|
||||
mBorderRGB.getRaw(Spacing.ALL) : DEFAULT_BORDER_RGB;
|
||||
float alpha = (mBorderAlpha != null && !YogaConstants.isUndefined(mBorderAlpha.getRaw(Spacing.ALL))) ?
|
||||
mBorderAlpha.getRaw(Spacing.ALL) : DEFAULT_BORDER_ALPHA;
|
||||
return ReactViewBackgroundDrawable.colorFromAlphaAndRGBComponents(alpha, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if all the set border colors are equal. Bitwise AND all the set colors
|
||||
* together, then OR them all together. If the AND and the OR are the same, then the colors
|
||||
|
@ -547,10 +862,6 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
|
||||
// If the path drawn previously is of the same color,
|
||||
// there would be a slight white space between borders
|
||||
// with anti-alias set to true.
|
||||
|
@ -562,48 +873,56 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
int width = bounds.width();
|
||||
int height = bounds.height();
|
||||
|
||||
if (borderLeft > 0 && colorLeft != Color.TRANSPARENT) {
|
||||
mPaint.setColor(colorLeft);
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, top);
|
||||
mPathForBorder.lineTo(left + borderLeft, top + borderTop);
|
||||
mPathForBorder.lineTo(left + borderLeft, top + height - borderBottom);
|
||||
mPathForBorder.lineTo(left, top + height);
|
||||
mPathForBorder.lineTo(left, top);
|
||||
canvas.drawPath(mPathForBorder, mPaint);
|
||||
if (borderLeft > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = top;
|
||||
final float x2 = left + borderLeft;
|
||||
final float y2 = top + borderTop;
|
||||
final float x3 = left + borderLeft;
|
||||
final float y3 = top + height - borderBottom;
|
||||
final float x4 = left;
|
||||
final float y4 = top + height;
|
||||
|
||||
drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderTop > 0 && colorTop != Color.TRANSPARENT) {
|
||||
mPaint.setColor(colorTop);
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, top);
|
||||
mPathForBorder.lineTo(left + borderLeft, top + borderTop);
|
||||
mPathForBorder.lineTo(left + width - borderRight, top + borderTop);
|
||||
mPathForBorder.lineTo(left + width, top);
|
||||
mPathForBorder.lineTo(left, top);
|
||||
canvas.drawPath(mPathForBorder, mPaint);
|
||||
if (borderTop > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = top;
|
||||
final float x2 = left + borderLeft;
|
||||
final float y2 = top + borderTop;
|
||||
final float x3 = left + width - borderRight;
|
||||
final float y3 = top + borderTop;
|
||||
final float x4 = left + width;
|
||||
final float y4 = top;
|
||||
|
||||
drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderRight > 0 && colorRight != Color.TRANSPARENT) {
|
||||
mPaint.setColor(colorRight);
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left + width, top);
|
||||
mPathForBorder.lineTo(left + width, top + height);
|
||||
mPathForBorder.lineTo(left + width - borderRight, top + height - borderBottom);
|
||||
mPathForBorder.lineTo(left + width - borderRight, top + borderTop);
|
||||
mPathForBorder.lineTo(left + width, top);
|
||||
canvas.drawPath(mPathForBorder, mPaint);
|
||||
if (borderRight > 0) {
|
||||
final float x1 = left + width;
|
||||
final float y1 = top;
|
||||
final float x2 = left + width;
|
||||
final float y2 = top + height;
|
||||
final float x3 = left + width - borderRight;
|
||||
final float y3 = top + height - borderBottom;
|
||||
final float x4 = left + width - borderRight;
|
||||
final float y4 = top + borderTop;
|
||||
|
||||
drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
if (borderBottom > 0 && colorBottom != Color.TRANSPARENT) {
|
||||
mPaint.setColor(colorBottom);
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, top + height);
|
||||
mPathForBorder.lineTo(left + width, top + height);
|
||||
mPathForBorder.lineTo(left + width - borderRight, top + height - borderBottom);
|
||||
mPathForBorder.lineTo(left + borderLeft, top + height - borderBottom);
|
||||
mPathForBorder.lineTo(left, top + height);
|
||||
canvas.drawPath(mPathForBorder, mPaint);
|
||||
if (borderBottom > 0) {
|
||||
final float x1 = left;
|
||||
final float y1 = top + height;
|
||||
final float x2 = left + width;
|
||||
final float y2 = top + height;
|
||||
final float x3 = left + width - borderRight;
|
||||
final float y3 = top + height - borderBottom;
|
||||
final float x4 = left + borderLeft;
|
||||
final float y4 = top + height - borderBottom;
|
||||
|
||||
drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
// re-enable anti alias
|
||||
|
@ -612,6 +931,35 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||
}
|
||||
}
|
||||
|
||||
private void drawQuadrilateral(
|
||||
Canvas canvas,
|
||||
int fillColor,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3,
|
||||
float x4,
|
||||
float y4) {
|
||||
if (fillColor == Color.TRANSPARENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
|
||||
mPaint.setColor(fillColor);
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(x1, y1);
|
||||
mPathForBorder.lineTo(x2, y2);
|
||||
mPathForBorder.lineTo(x3, y3);
|
||||
mPathForBorder.lineTo(x4, y4);
|
||||
mPathForBorder.lineTo(x1, y1);
|
||||
canvas.drawPath(mPathForBorder, mPaint);
|
||||
}
|
||||
|
||||
private int getBorderWidth(int position) {
|
||||
return mBorderWidth != null ? Math.round(mBorderWidth.get(position)) : 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue