Experiment to allow animating fillOpacity of Rect using native driver.

import React, { Component } from 'react';
import { StyleSheet, View, Dimensions, Animated } from 'react-native';
import { Svg, Rect } from 'react-native-svg';

const { width, height } = Dimensions.get('window');
const AnimatedRect = Animated.createAnimatedComponent(Rect);

export default class App extends Component {
  state = {
    anim: new Animated.Value(0),
  };

  componentDidMount() {
    Animated.timing(this.state.anim, {
      toValue: 1,
      duration: 3000,
      useNativeDriver: true,
    }).start();
  }

  render() {
    const { anim } = this.state;
    return (
      <View style={styles.container}>
        <Svg width={width} height={height} viewBox="0 0 100 100">
          <AnimatedRect
            x="5"
            y="5"
            width="90"
            height="90"
            fill="green"
            fillOpacity={anim}
          />
        </Svg>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#ecf0f1',
  },
});
This commit is contained in:
Mikael Sand
2018-02-24 23:18:50 +02:00
parent f3ea54cd26
commit fbd6591251
11 changed files with 95 additions and 44 deletions

View File

@@ -40,14 +40,14 @@ class RectShadowNode extends RenderableShadowNode {
markUpdated();
}
@ReactProp(name = "width")
@ReactProp(name = "rectwidth")
public void setWidth(String width) {
mW = width;
markUpdated();
}
@ReactProp(name = "height")
@ReactProp(name = "rectheight")
public void setHeight(String height) {
mH = height;
markUpdated();

View File

@@ -9,18 +9,19 @@
package com.horcrux.svg;
import android.view.View;
import android.util.SparseArray;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
/**
* ViewManager for all shadowed RNSVG views: Group, Path and Text. Since these never get rendered
* into native views and don't need any logic (all the logic is in {@link SvgView}), this
* "stubbed" ViewManager is used for all of them.
*/
class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
class RenderableViewManager extends ViewGroupManager<RenderableView> {
/* package */ private static final String CLASS_GROUP = "RNSVGGroup";
/* package */ private static final String CLASS_PATH = "RNSVGPath";
@@ -195,17 +196,43 @@ class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
}
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
throw new IllegalStateException("SVG elements does not map into a native view");
@ReactProp(name = "fillOpacity")
public void setFillOpacity(RenderableView node, float opacity) {
RenderableShadowNode shadow = ((RenderableShadowNode)mTagToShadowNode.get(node.getId()));
shadow.setFillOpacity(opacity);
SvgViewShadowNode view = shadow.getSvgShadowNode();
if (view != null ) view.queueDraw();
}
@Override
public void updateExtraData(View root, Object extraData) {
throw new IllegalStateException("SVG elements does not map into a native view");
protected RenderableView createViewInstance(ThemedReactContext reactContext) {
return new RenderableView(reactContext);
}
@Override
public void onDropViewInstance(View view) {
public void updateExtraData(RenderableView root, Object extraData) {
throw new IllegalStateException("SVG elements does not map into a native view");
}
private static final SparseArray<VirtualNode> mTagToShadowNode = new SparseArray<>();
private static final SparseArray<RenderableView> mTagToSvgView = new SparseArray<>();
@Override
public void onDropViewInstance(RenderableView view) {
int tag = view.getId();
mTagToShadowNode.remove(tag);
mTagToSvgView.remove(tag);
}
public static void setView(RenderableView renderableView) {
mTagToSvgView.put(renderableView.getId(), renderableView);
}
static void setShadowNode(VirtualNode virtualNode) {
mTagToShadowNode.put(virtualNode.getReactTag(), virtualNode);
}
static VirtualNode getShadowNodeByTag(int id) {
return mTagToShadowNode.get(id);
}
}

View File

@@ -67,6 +67,12 @@ public class SvgView extends ViewGroup {
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
}
public void addView(View child, int index, LayoutParams params) {
if (!(child instanceof RenderableView)) {
super.addView(child, index, params);
}
}
/**
* Sets the {@link TextureView.SurfaceTextureListener} used to listen to surface
* texture events.
@@ -111,9 +117,7 @@ public class SvgView extends ViewGroup {
ReactShadowNodeImpl node = getShadowNode();
for (int i = 0; i < this.getChildCount(); i++) {
View child = this.getChildAt(i);
if (child instanceof TextureView) {
child.layout(l, t, r , b);
} else if (child instanceof ReactViewGroup) {
if (child instanceof ReactViewGroup) {
int id = child.getId();
for (int j = 0; j < node.getChildCount(); j++) {
ReactShadowNodeImpl nodeChild = node.getChildAt(j);
@@ -129,6 +133,8 @@ public class SvgView extends ViewGroup {
child.layout(Math.round(x), Math.round(y), Math.round(nr), Math.round(nb));
break;
}
} else {
child.layout(l, t, r , b);
}
}
}

View File

@@ -21,6 +21,7 @@ import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.Typeface;
import android.util.Base64;
import android.view.Choreographer;
import android.view.Surface;
import android.view.TextureView;
@@ -43,7 +44,7 @@ import javax.annotation.Nullable;
* Shadow node for RNSVG virtual tree root - RNSVGSvgView
*/
public class SvgViewShadowNode extends LayoutShadowNode
implements TextureView.SurfaceTextureListener {
implements TextureView.SurfaceTextureListener, Choreographer.FrameCallback {
private @Nullable Surface mSurface;
@@ -337,4 +338,21 @@ public class SvgViewShadowNode extends LayoutShadowNode
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
private boolean queued = false;
@Override
public void doFrame(long frameTimeNanos) {
if (queued) {
queued = false;
drawOutput();
}
}
void queueDraw() {
if (!queued) {
queued = true;
Choreographer.getInstance().postFrameCallback(this);
}
}
}

View File

@@ -38,6 +38,12 @@ abstract class VirtualNode extends LayoutShadowNode {
static final float MIN_OPACITY_FOR_DRAW = 0.01f;
@Override
public void setReactTag(int reactTag) {
super.setReactTag(reactTag);
RenderableViewManager.setShadowNode(this);
}
private static final float[] sRawMatrix = new float[]{
1, 0, 0,
0, 1, 0,
@@ -72,18 +78,17 @@ abstract class VirtualNode extends LayoutShadowNode {
Path mClipRegionPath;
VirtualNode() {
setIsLayoutOnly(true);
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
}
@Override
public boolean isVirtual() {
return true;
return false;
}
@Override
public boolean isVirtualAnchor() {
return true;
return false;
}
@Override

View File

@@ -44,8 +44,8 @@ export default class extends Shape {
}, this)}
x={props.x.toString()}
y={props.y.toString()}
width={props.width.toString()}
height={props.height.toString()}
rectwidth={props.width.toString()}
rectheight={props.height.toString()}
rx={props.rx.toString()}
ry={props.ry.toString()}
/>;

View File

@@ -14,8 +14,8 @@
@property (nonatomic, strong) NSString* x;
@property (nonatomic, strong) NSString* y;
@property (nonatomic, strong) NSString* width;
@property (nonatomic, strong) NSString* height;
@property (nonatomic, strong) NSString* rectwidth;
@property (nonatomic, strong) NSString* rectheight;
@property (nonatomic, strong) NSString* rx;
@property (nonatomic, strong) NSString* ry;

View File

@@ -29,22 +29,22 @@
_y = y;
}
- (void)setWidth:(NSString *)width
- (void)setWidth:(NSString *)rectwidth
{
if (width == _width) {
if (rectwidth == _rectwidth) {
return;
}
[self invalidate];
_width = width;
_rectwidth = rectwidth;
}
- (void)setHeight:(NSString *)height
- (void)setHeight:(NSString *)rectheight
{
if (height == _height) {
if (rectheight == _rectheight) {
return;
}
[self invalidate];
_height = height;
_rectheight = rectheight;
}
- (void)setRx:(NSString *)rx
@@ -70,8 +70,8 @@
CGMutablePathRef path = CGPathCreateMutable();
CGFloat x = [self relativeOnWidth:self.x];
CGFloat y = [self relativeOnHeight:self.y];
CGFloat width = [self relativeOnWidth:self.width];
CGFloat height = [self relativeOnHeight:self.height];
CGFloat width = [self relativeOnWidth:self.rectwidth];
CGFloat height = [self relativeOnHeight:self.rectheight];
CGFloat rx = [self relativeOnWidth:self.rx];
CGFloat ry = [self relativeOnHeight:self.ry];

View File

@@ -24,11 +24,6 @@ RCT_EXPORT_MODULE()
return [self node];
}
- (RCTShadowView *)shadowView
{
return nil;
}
RCT_EXPORT_VIEW_PROPERTY(name, NSString)
RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(matrix, CGAffineTransform)

View File

@@ -22,8 +22,8 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(x, NSString)
RCT_EXPORT_VIEW_PROPERTY(y, NSString)
RCT_EXPORT_VIEW_PROPERTY(width, NSString)
RCT_EXPORT_VIEW_PROPERTY(height, NSString)
RCT_EXPORT_VIEW_PROPERTY(rectwidth, NSString)
RCT_EXPORT_VIEW_PROPERTY(rectheight, NSString)
RCT_EXPORT_VIEW_PROPERTY(rx, NSString)
RCT_EXPORT_VIEW_PROPERTY(ry, NSString)

View File

@@ -220,8 +220,8 @@ const RectAttributes = {
...RenderableAttributes,
x: true,
y: true,
width: true,
height: true,
rectwidth: true,
rectheight: true,
rx: true,
ry: true,
};