Added support for Image corner radii in Android
Summary:Split out from PR #4252 - kmagiera I've made the changes to how the radii arrays are allocated, is the approach I've taken correct? also it looks like ImageStylePropTypes are needed so I left them in for the moment. I suppose this pull request will only be valid if iOS supports image corner radii, but at least it's here if/when needed. Attached an image of how it handles the existing case: ![screen shot 2016-01-08 at 4 21 25 pm](https://cloud.githubusercontent.com/assets/1407729/12200126/d3caceac-b625-11e5-8281-06274732a281.png) Closes https://github.com/facebook/react-native/pull/5197 Differential Revision: D3138725 Pulled By: mkonicek fb-gh-sync-id: df772fd07fe85386ae4c681f9e79a19d2316d38b fbshipit-source-id: df772fd07fe85386ae4c681f9e79a19d2316d38b
This commit is contained in:
parent
855c0cc25e
commit
69534a3373
|
@ -55,6 +55,12 @@ var ImageStylePropTypes = {
|
||||||
* @platform android
|
* @platform android
|
||||||
*/
|
*/
|
||||||
overlayColor: ReactPropTypes.string,
|
overlayColor: ReactPropTypes.string,
|
||||||
|
|
||||||
|
// Android-Specific styles
|
||||||
|
borderTopLeftRadius: ReactPropTypes.number,
|
||||||
|
borderTopRightRadius: ReactPropTypes.number,
|
||||||
|
borderBottomLeftRadius: ReactPropTypes.number,
|
||||||
|
borderBottomRightRadius: ReactPropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ImageStylePropTypes;
|
module.exports = ImageStylePropTypes;
|
||||||
|
|
|
@ -6,6 +6,7 @@ android_library(
|
||||||
deps = [
|
deps = [
|
||||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||||
react_native_target('java/com/facebook/react/common:common'),
|
react_native_target('java/com/facebook/react/common:common'),
|
||||||
|
react_native_target('java/com/facebook/csslayout:csslayout'),
|
||||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||||
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
||||||
|
|
|
@ -16,10 +16,13 @@ import java.util.Map;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff.Mode;
|
import android.graphics.PorterDuff.Mode;
|
||||||
|
|
||||||
|
import com.facebook.csslayout.CSSConstants;
|
||||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||||
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
||||||
import com.facebook.react.common.MapBuilder;
|
import com.facebook.react.common.MapBuilder;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
import com.facebook.react.uimanager.PixelUtil;
|
||||||
|
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||||
import com.facebook.react.uimanager.SimpleViewManager;
|
import com.facebook.react.uimanager.SimpleViewManager;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.uimanager.ViewProps;
|
import com.facebook.react.uimanager.ViewProps;
|
||||||
|
@ -106,9 +109,23 @@ public class ReactImageManager extends SimpleViewManager<ReactImageView> {
|
||||||
view.setBorderWidth(borderWidth);
|
view.setBorderWidth(borderWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "borderRadius")
|
@ReactPropGroup(names = {
|
||||||
public void setBorderRadius(ReactImageView view, float borderRadius) {
|
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(ReactImageView view, int index, float borderRadius) {
|
||||||
|
if (!CSSConstants.isUndefined(borderRadius)) {
|
||||||
|
borderRadius = PixelUtil.toPixelFromDIP(borderRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
view.setBorderRadius(borderRadius);
|
view.setBorderRadius(borderRadius);
|
||||||
|
} else {
|
||||||
|
view.setBorderRadius(borderRadius, index - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = ViewProps.RESIZE_MODE)
|
@ReactProp(name = ViewProps.RESIZE_MODE)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Shader;
|
import android.graphics.Shader;
|
||||||
|
@ -26,6 +27,8 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.facebook.common.util.UriUtil;
|
import com.facebook.common.util.UriUtil;
|
||||||
|
import com.facebook.csslayout.CSSConstants;
|
||||||
|
import com.facebook.csslayout.FloatUtil;
|
||||||
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
||||||
import com.facebook.drawee.controller.BaseControllerListener;
|
import com.facebook.drawee.controller.BaseControllerListener;
|
||||||
import com.facebook.drawee.controller.ControllerListener;
|
import com.facebook.drawee.controller.ControllerListener;
|
||||||
|
@ -48,6 +51,8 @@ import com.facebook.react.uimanager.PixelUtil;
|
||||||
import com.facebook.react.uimanager.UIManagerModule;
|
import com.facebook.react.uimanager.UIManagerModule;
|
||||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class around Fresco's GenericDraweeView, enabling persisting props across multiple view
|
* Wrapper class around Fresco's GenericDraweeView, enabling persisting props across multiple view
|
||||||
* update and consistent processing of both static and network images.
|
* update and consistent processing of both static and network images.
|
||||||
|
@ -56,6 +61,8 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
|
|
||||||
public static final int REMOTE_IMAGE_FADE_DURATION_MS = 300;
|
public static final int REMOTE_IMAGE_FADE_DURATION_MS = 300;
|
||||||
|
|
||||||
|
private static float[] sComputedCornerRadii = new float[4];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation note re rounded corners:
|
* Implementation note re rounded corners:
|
||||||
*
|
*
|
||||||
|
@ -72,7 +79,7 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
|
|
||||||
private class RoundedCornerPostprocessor extends BasePostprocessor {
|
private class RoundedCornerPostprocessor extends BasePostprocessor {
|
||||||
|
|
||||||
float getRadius(Bitmap source) {
|
void getRadii(Bitmap source, float[] computedCornerRadii, float[] mappedRadii) {
|
||||||
ScalingUtils.getTransform(
|
ScalingUtils.getTransform(
|
||||||
sMatrix,
|
sMatrix,
|
||||||
new Rect(0, 0, source.getWidth(), source.getHeight()),
|
new Rect(0, 0, source.getWidth(), source.getHeight()),
|
||||||
|
@ -82,13 +89,29 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
0.0f,
|
0.0f,
|
||||||
mScaleType);
|
mScaleType);
|
||||||
sMatrix.invert(sInverse);
|
sMatrix.invert(sInverse);
|
||||||
return sInverse.mapRadius(mBorderRadius);
|
|
||||||
|
mappedRadii[0] = sInverse.mapRadius(computedCornerRadii[0]);
|
||||||
|
mappedRadii[1] = mappedRadii[0];
|
||||||
|
|
||||||
|
mappedRadii[2] = sInverse.mapRadius(computedCornerRadii[1]);
|
||||||
|
mappedRadii[3] = mappedRadii[2];
|
||||||
|
|
||||||
|
mappedRadii[4] = sInverse.mapRadius(computedCornerRadii[2]);
|
||||||
|
mappedRadii[5] = mappedRadii[4];
|
||||||
|
|
||||||
|
mappedRadii[6] = sInverse.mapRadius(computedCornerRadii[3]);
|
||||||
|
mappedRadii[7] = mappedRadii[6];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Bitmap output, Bitmap source) {
|
public void process(Bitmap output, Bitmap source) {
|
||||||
|
cornerRadii(sComputedCornerRadii);
|
||||||
|
|
||||||
output.setHasAlpha(true);
|
output.setHasAlpha(true);
|
||||||
if (mBorderRadius < 0.01f) {
|
if (FloatUtil.floatsEqual(sComputedCornerRadii[0], 0f) &&
|
||||||
|
FloatUtil.floatsEqual(sComputedCornerRadii[1], 0f) &&
|
||||||
|
FloatUtil.floatsEqual(sComputedCornerRadii[2], 0f) &&
|
||||||
|
FloatUtil.floatsEqual(sComputedCornerRadii[3], 0f)) {
|
||||||
super.process(output, source);
|
super.process(output, source);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -96,12 +119,19 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
|
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
|
||||||
Canvas canvas = new Canvas(output);
|
Canvas canvas = new Canvas(output);
|
||||||
float radius = getRadius(source);
|
|
||||||
canvas.drawRoundRect(
|
float[] radii = new float[8];
|
||||||
|
|
||||||
|
getRadii(source, sComputedCornerRadii, radii);
|
||||||
|
|
||||||
|
Path pathForBorderRadius = new Path();
|
||||||
|
|
||||||
|
pathForBorderRadius.addRoundRect(
|
||||||
new RectF(0, 0, source.getWidth(), source.getHeight()),
|
new RectF(0, 0, source.getWidth(), source.getHeight()),
|
||||||
radius,
|
radii,
|
||||||
radius,
|
Path.Direction.CW);
|
||||||
paint);
|
|
||||||
|
canvas.drawPath(pathForBorderRadius, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +140,8 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
private int mBorderColor;
|
private int mBorderColor;
|
||||||
private int mOverlayColor;
|
private int mOverlayColor;
|
||||||
private float mBorderWidth;
|
private float mBorderWidth;
|
||||||
private float mBorderRadius;
|
private float mBorderRadius = CSSConstants.UNDEFINED;
|
||||||
|
private @Nullable float[] mBorderCornerRadii;
|
||||||
private ScalingUtils.ScaleType mScaleType;
|
private ScalingUtils.ScaleType mScaleType;
|
||||||
private boolean mIsDirty;
|
private boolean mIsDirty;
|
||||||
private boolean mIsLocalImage;
|
private boolean mIsLocalImage;
|
||||||
|
@ -198,9 +229,23 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBorderRadius(float borderRadius) {
|
public void setBorderRadius(float borderRadius) {
|
||||||
mBorderRadius = PixelUtil.toPixelFromDIP(borderRadius);
|
if (!FloatUtil.floatsEqual(mBorderRadius, borderRadius)) {
|
||||||
|
mBorderRadius = borderRadius;
|
||||||
mIsDirty = true;
|
mIsDirty = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBorderRadius(float borderRadius, int position) {
|
||||||
|
if (mBorderCornerRadii == null) {
|
||||||
|
mBorderCornerRadii = new float[4];
|
||||||
|
Arrays.fill(mBorderCornerRadii, CSSConstants.UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FloatUtil.floatsEqual(mBorderCornerRadii[position], borderRadius)) {
|
||||||
|
mBorderCornerRadii[position] = borderRadius;
|
||||||
|
mIsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setScaleType(ScalingUtils.ScaleType scaleType) {
|
public void setScaleType(ScalingUtils.ScaleType scaleType) {
|
||||||
mScaleType = scaleType;
|
mScaleType = scaleType;
|
||||||
|
@ -250,6 +295,15 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
// no worth marking as dirty if it already rendered..
|
// no worth marking as dirty if it already rendered..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cornerRadii(float[] computedCorners) {
|
||||||
|
float defaultBorderRadius = !CSSConstants.isUndefined(mBorderRadius) ? mBorderRadius : 0;
|
||||||
|
|
||||||
|
computedCorners[0] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[0]) ? mBorderCornerRadii[0] : defaultBorderRadius;
|
||||||
|
computedCorners[1] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[1]) ? mBorderCornerRadii[1] : defaultBorderRadius;
|
||||||
|
computedCorners[2] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius;
|
||||||
|
computedCorners[3] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius;
|
||||||
|
}
|
||||||
|
|
||||||
public void maybeUpdateView() {
|
public void maybeUpdateView() {
|
||||||
if (!mIsDirty) {
|
if (!mIsDirty) {
|
||||||
return;
|
return;
|
||||||
|
@ -271,10 +325,17 @@ public class ReactImageView extends GenericDraweeView {
|
||||||
boolean usePostprocessorScaling =
|
boolean usePostprocessorScaling =
|
||||||
mScaleType != ScalingUtils.ScaleType.CENTER_CROP &&
|
mScaleType != ScalingUtils.ScaleType.CENTER_CROP &&
|
||||||
mScaleType != ScalingUtils.ScaleType.FOCUS_CROP;
|
mScaleType != ScalingUtils.ScaleType.FOCUS_CROP;
|
||||||
float hierarchyRadius = usePostprocessorScaling ? 0 : mBorderRadius;
|
|
||||||
|
|
||||||
RoundingParams roundingParams = hierarchy.getRoundingParams();
|
RoundingParams roundingParams = hierarchy.getRoundingParams();
|
||||||
roundingParams.setCornersRadius(hierarchyRadius);
|
|
||||||
|
if (usePostprocessorScaling) {
|
||||||
|
roundingParams.setCornersRadius(0);
|
||||||
|
} else {
|
||||||
|
cornerRadii(sComputedCornerRadii);
|
||||||
|
|
||||||
|
roundingParams.setCornersRadii(sComputedCornerRadii[0], sComputedCornerRadii[1], sComputedCornerRadii[2], sComputedCornerRadii[3]);
|
||||||
|
}
|
||||||
|
|
||||||
roundingParams.setBorder(mBorderColor, mBorderWidth);
|
roundingParams.setBorder(mBorderColor, mBorderWidth);
|
||||||
if (mOverlayColor != Color.TRANSPARENT) {
|
if (mOverlayColor != Color.TRANSPARENT) {
|
||||||
roundingParams.setOverlayColor(mOverlayColor);
|
roundingParams.setOverlayColor(mOverlayColor);
|
||||||
|
|
Loading…
Reference in New Issue