mirror of
https://github.com/status-im/react-native.git
synced 2025-02-20 21:28:08 +00:00
Implement border width, color, radius and style in RCTView
Summary: @public Initial implementation of RCTView doesn't support borders, this diff fixes it by implementing a `DrawBorder`. Reviewed By: sriramramani Differential Revision: D2564424
This commit is contained in:
parent
71ca522c68
commit
1c7f23c79d
@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.flat;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import com.facebook.csslayout.Spacing;
|
||||
|
||||
/* package */ final class DrawBorder extends AbstractDrawBorder {
|
||||
|
||||
private static final Paint PAINT = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private static final float[] TMP_FLOAT_ARRAY = new float[4];
|
||||
|
||||
private static final int BORDER_STYLE_SOLID = 0;
|
||||
private static final int BORDER_STYLE_DOTTED = 1;
|
||||
private static final int BORDER_STYLE_DASHED = 2;
|
||||
|
||||
private static final int BORDER_LEFT_COLOR_SET = 1 << 1;
|
||||
private static final int BORDER_TOP_COLOR_SET = 1 << 2;
|
||||
private static final int BORDER_RIGHT_COLOR_SET = 1 << 3;
|
||||
private static final int BORDER_BOTTOM_COLOR_SET = 1 << 4;
|
||||
private static final int BORDER_PATH_EFFECT_DIRTY = 1 << 5;
|
||||
|
||||
private float mBorderLeftWidth;
|
||||
private float mBorderTopWidth;
|
||||
private float mBorderRightWidth;
|
||||
private float mBorderBottomWidth;
|
||||
|
||||
private int mBorderLeftColor;
|
||||
private int mBorderTopColor;
|
||||
private int mBorderRightColor;
|
||||
private int mBorderBottomColor;
|
||||
|
||||
private int mBorderStyle = BORDER_STYLE_SOLID;
|
||||
|
||||
private int mBackgroundColor;
|
||||
|
||||
private @Nullable DashPathEffect mPathEffectForBorderStyle;
|
||||
|
||||
public void setBorderWidth(int position, float borderWidth) {
|
||||
switch (position) {
|
||||
case Spacing.LEFT:
|
||||
mBorderLeftWidth = borderWidth;
|
||||
break;
|
||||
case Spacing.TOP:
|
||||
mBorderTopWidth = borderWidth;
|
||||
break;
|
||||
case Spacing.RIGHT:
|
||||
mBorderRightWidth = borderWidth;
|
||||
break;
|
||||
case Spacing.BOTTOM:
|
||||
mBorderBottomWidth = borderWidth;
|
||||
break;
|
||||
case Spacing.ALL:
|
||||
setBorderWidth(borderWidth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public float getBorderWidth(int position) {
|
||||
switch (position) {
|
||||
case Spacing.LEFT:
|
||||
return mBorderLeftWidth;
|
||||
case Spacing.TOP:
|
||||
return mBorderTopWidth;
|
||||
case Spacing.RIGHT:
|
||||
return mBorderRightWidth;
|
||||
case Spacing.BOTTOM:
|
||||
return mBorderBottomWidth;
|
||||
case Spacing.ALL:
|
||||
return getBorderWidth();
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public void setBorderStyle(@Nullable String style) {
|
||||
if ("dotted".equals(style)) {
|
||||
mBorderStyle = BORDER_STYLE_DOTTED;
|
||||
} else if ("dashed".equals(style)) {
|
||||
mBorderStyle = BORDER_STYLE_DASHED;
|
||||
} else {
|
||||
mBorderStyle = BORDER_STYLE_SOLID;
|
||||
}
|
||||
|
||||
setFlag(BORDER_PATH_EFFECT_DIRTY);
|
||||
}
|
||||
|
||||
public void resetBorderColor(int position) {
|
||||
switch (position) {
|
||||
case Spacing.LEFT:
|
||||
resetFlag(BORDER_LEFT_COLOR_SET);
|
||||
break;
|
||||
case Spacing.TOP:
|
||||
resetFlag(BORDER_TOP_COLOR_SET);
|
||||
break;
|
||||
case Spacing.RIGHT:
|
||||
resetFlag(BORDER_RIGHT_COLOR_SET);
|
||||
break;
|
||||
case Spacing.BOTTOM:
|
||||
resetFlag(BORDER_BOTTOM_COLOR_SET);
|
||||
break;
|
||||
case Spacing.ALL:
|
||||
setBorderColor(Color.BLACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBorderColor(int position, int borderColor) {
|
||||
switch (position) {
|
||||
case Spacing.LEFT:
|
||||
mBorderLeftColor = borderColor;
|
||||
setFlag(BORDER_LEFT_COLOR_SET);
|
||||
break;
|
||||
case Spacing.TOP:
|
||||
mBorderTopColor = borderColor;
|
||||
setFlag(BORDER_TOP_COLOR_SET);
|
||||
break;
|
||||
case Spacing.RIGHT:
|
||||
mBorderRightColor = borderColor;
|
||||
setFlag(BORDER_RIGHT_COLOR_SET);
|
||||
break;
|
||||
case Spacing.BOTTOM:
|
||||
mBorderBottomColor = borderColor;
|
||||
setFlag(BORDER_BOTTOM_COLOR_SET);
|
||||
break;
|
||||
case Spacing.ALL:
|
||||
setBorderColor(borderColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int getBorderColor(int position) {
|
||||
int defaultColor = getBorderColor();
|
||||
switch (position) {
|
||||
case Spacing.LEFT:
|
||||
return resolveBorderColor(BORDER_LEFT_COLOR_SET, mBorderLeftColor, defaultColor);
|
||||
case Spacing.TOP:
|
||||
return resolveBorderColor(BORDER_TOP_COLOR_SET, mBorderTopColor, defaultColor);
|
||||
case Spacing.RIGHT:
|
||||
return resolveBorderColor(BORDER_RIGHT_COLOR_SET, mBorderRightColor, defaultColor);
|
||||
case Spacing.BOTTOM:
|
||||
return resolveBorderColor(BORDER_BOTTOM_COLOR_SET, mBorderBottomColor, defaultColor);
|
||||
case Spacing.ALL:
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
public void setBackgroundColor(int backgroundColor) {
|
||||
mBackgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return mBackgroundColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (getBorderRadius() >= 0.5f) {
|
||||
drawRoundedBorders(canvas);
|
||||
} else {
|
||||
drawRectangularBorders(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable DashPathEffect getPathEffectForBorderStyle() {
|
||||
if (isFlagSet(BORDER_PATH_EFFECT_DIRTY)) {
|
||||
switch (mBorderStyle) {
|
||||
case BORDER_STYLE_DOTTED:
|
||||
mPathEffectForBorderStyle = createDashPathEffect(getBorderWidth());
|
||||
break;
|
||||
|
||||
case BORDER_STYLE_DASHED:
|
||||
mPathEffectForBorderStyle = createDashPathEffect(getBorderWidth() * 3);
|
||||
break;
|
||||
|
||||
default:
|
||||
mPathEffectForBorderStyle = null;
|
||||
break;
|
||||
}
|
||||
|
||||
resetFlag(BORDER_PATH_EFFECT_DIRTY);
|
||||
}
|
||||
|
||||
return mPathEffectForBorderStyle;
|
||||
}
|
||||
|
||||
private void drawRoundedBorders(Canvas canvas) {
|
||||
if (mBackgroundColor != 0) {
|
||||
PAINT.setColor(mBackgroundColor);
|
||||
canvas.drawPath(getPathForBorderRadius(), PAINT);
|
||||
return;
|
||||
}
|
||||
|
||||
drawBorders(canvas);
|
||||
}
|
||||
|
||||
private void drawRectangularBorders(Canvas canvas) {
|
||||
int defaultColor = getBorderColor();
|
||||
float defaultWidth = getBorderWidth();
|
||||
|
||||
// draw top
|
||||
float topWidth = resolveWidth(mBorderTopWidth, defaultWidth);
|
||||
float bottomOfTheTop = getTop() + topWidth;
|
||||
int topColor = resolveBorderColor(BORDER_TOP_COLOR_SET, mBorderTopColor, defaultColor);
|
||||
if (Color.alpha(topColor) != 0 && topWidth != 0) {
|
||||
PAINT.setColor(topColor);
|
||||
canvas.drawRect(getLeft(), getTop(), getRight(), bottomOfTheTop, PAINT);
|
||||
}
|
||||
|
||||
// draw bottom
|
||||
float bottomWidth = resolveWidth(mBorderBottomWidth, defaultWidth);
|
||||
float topOfTheBottom = getBottom() - bottomWidth;
|
||||
int bottomColor = resolveBorderColor(BORDER_BOTTOM_COLOR_SET, mBorderBottomColor, defaultColor);
|
||||
if (Color.alpha(bottomColor) != 0 && bottomWidth != 0) {
|
||||
PAINT.setColor(bottomColor);
|
||||
canvas.drawRect(getLeft(), topOfTheBottom, getRight(), getBottom(), PAINT);
|
||||
}
|
||||
|
||||
// draw left
|
||||
float leftWidth = resolveWidth(mBorderLeftWidth, defaultWidth);
|
||||
float rightOfTheLeft = getLeft() + leftWidth;
|
||||
int leftColor = resolveBorderColor(BORDER_LEFT_COLOR_SET, mBorderLeftColor, defaultColor);
|
||||
if (Color.alpha(leftColor) != 0 && leftWidth != 0) {
|
||||
canvas.drawRect(getLeft(), bottomOfTheTop, rightOfTheLeft, topOfTheBottom, PAINT);
|
||||
}
|
||||
|
||||
// draw right
|
||||
float rightWidth = resolveWidth(mBorderRightWidth, defaultWidth);
|
||||
float leftOfTheRight = getRight() - rightWidth;
|
||||
int rightColor = resolveBorderColor(BORDER_RIGHT_COLOR_SET, mBorderRightColor, defaultColor);
|
||||
if (Color.alpha(rightColor) != 0 && rightWidth != 0) {
|
||||
PAINT.setColor(rightColor);
|
||||
canvas.drawRect(leftOfTheRight, bottomOfTheTop, getRight(), topOfTheBottom, PAINT);
|
||||
}
|
||||
|
||||
// draw center
|
||||
if (Color.alpha(mBackgroundColor) != 0) {
|
||||
PAINT.setColor(mBackgroundColor);
|
||||
canvas.drawRect(rightOfTheLeft, bottomOfTheTop, leftOfTheRight, topOfTheBottom, PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
private int resolveBorderColor(int flag, int color, int defaultColor) {
|
||||
return isFlagSet(flag) ? color : defaultColor;
|
||||
}
|
||||
|
||||
private static float resolveWidth(float width, float defaultWidth) {
|
||||
return width == 0 ? defaultWidth : width;
|
||||
}
|
||||
|
||||
private static DashPathEffect createDashPathEffect(float borderWidth) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
TMP_FLOAT_ARRAY[i] = borderWidth;
|
||||
}
|
||||
return new DashPathEffect(TMP_FLOAT_ARRAY, 0);
|
||||
}
|
||||
}
|
@ -9,8 +9,73 @@
|
||||
|
||||
package com.facebook.react.flat;
|
||||
|
||||
/**
|
||||
* Dummy implementation of RCTView.
|
||||
*/
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactProp;
|
||||
import com.facebook.react.uimanager.ReactPropGroup;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
|
||||
/* package */ final class RCTView extends FlatShadowNode {
|
||||
|
||||
private @Nullable DrawBorder mDrawBorder;
|
||||
|
||||
@Override
|
||||
protected void collectState(
|
||||
StateBuilder stateBuilder,
|
||||
float left,
|
||||
float top,
|
||||
float right,
|
||||
float bottom) {
|
||||
super.collectState(stateBuilder, left, top, right, bottom);
|
||||
|
||||
if (mDrawBorder != null) {
|
||||
mDrawBorder = (DrawBorder) mDrawBorder.updateBoundsAndFreeze(left, top, right, bottom);
|
||||
stateBuilder.addDrawCommand(mDrawBorder);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBackgroundColor(int backgroundColor) {
|
||||
getMutableBorder().setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderWidths(int index, float borderWidth) {
|
||||
super.setBorderWidths(index, borderWidth);
|
||||
|
||||
int type = ViewProps.BORDER_SPACING_TYPES[index];
|
||||
getMutableBorder().setBorderWidth(type, PixelUtil.toPixelFromDIP(borderWidth));
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor"
|
||||
}, customType = "Color", defaultDouble = Double.NaN)
|
||||
public void setBorderColor(int index, double color) {
|
||||
int type = ViewProps.BORDER_SPACING_TYPES[index];
|
||||
if (Double.isNaN(color)) {
|
||||
getMutableBorder().resetBorderColor(type);
|
||||
} else {
|
||||
getMutableBorder().setBorderColor(type, (int) color);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "borderRadius")
|
||||
public void setBorderRadius(float borderRadius) {
|
||||
getMutableBorder().setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius));
|
||||
}
|
||||
|
||||
@ReactProp(name = "borderStyle")
|
||||
public void setBorderStyle(@Nullable String borderStyle) {
|
||||
getMutableBorder().setBorderStyle(borderStyle);
|
||||
}
|
||||
|
||||
private DrawBorder getMutableBorder() {
|
||||
if (mDrawBorder == null) {
|
||||
mDrawBorder = new DrawBorder();
|
||||
} else if (mDrawBorder.isFrozen()) {
|
||||
mDrawBorder = (DrawBorder) mDrawBorder.mutableCopy();
|
||||
}
|
||||
invalidate();
|
||||
return mDrawBorder;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user