Implement support for animating gradient stops, fixes #884

```jsx
import * as React from 'react';
import { View, StyleSheet, Animated } from 'react-native';
import { Svg, Defs, LinearGradient, Stop, Rect } from 'react-native-svg';

const AnimatedStop = Animated.createAnimatedComponent(Stop);

export default class App extends React.Component {
  state = {
    anim: new Animated.Value(0),
  };
  componentDidMount = () => {
    Animated.timing(this.state.anim, {
      duration: 3000,
      toValue: 1,
    }).start();
  };
  render() {
    return (
      <View style={styles.container}>
        <Svg width="100%" height="100%">
          <Defs>
            <LinearGradient id="grad" x1="0" y1="50" x2="100" y2="50">
              <Stop offset="0%" stopColor="#888" stopOpacity="1" />
              <AnimatedStop
                offset={this.state.anim}
                stopColor="#888"
                stopOpacity="0.1"
              />
              <Stop offset="100%" stopColor="#888" stopOpacity="1" />
            </LinearGradient>
          </Defs>
          <Rect
            x="10"
            y="20"
            rx="16"
            ry="16"
            width="96"
            height="32"
            fill="url(#grad)"
          />
        </Svg>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#ecf0f1',
  },
});
```
This commit is contained in:
Mikael Sand
2019-01-23 17:09:35 +02:00
parent 2c04da063b
commit eb3e67a257
12 changed files with 37 additions and 7 deletions
+21 -5
View File
@@ -1,4 +1,4 @@
import { Children } from "react";
import React, { Children } from "react";
import Color from "color";
import extractOpacity from "./extractOpacity";
@@ -11,6 +11,12 @@ function percentToFloat(percent) {
if (typeof percent === "number") {
return percent;
}
if (
typeof percent === "object" &&
typeof percent.__getAnimatedValue === "function"
) {
return percent.__getAnimatedValue();
}
const matched = percent.match(percentReg);
if (!matched) {
console.warn(
@@ -24,20 +30,27 @@ function percentToFloat(percent) {
const offsetComparator = (object, other) => object[0] - other[0];
export default function extractGradient(props) {
export default function extractGradient(props, parent) {
const { id, children, gradientTransform, transform, gradientUnits } = props;
if (!id) {
return null;
}
const stops = [];
const childArray = Children.toArray(children);
const childArray = React.Children.map(children, child =>
React.cloneElement(child, {
parent,
}),
);
const l = childArray.length;
for (let i = 0; i < l; i++) {
const { props: { offset, stopColor, stopOpacity } } = childArray[i];
const offsetNumber = percentToFloat(offset);
if (stopColor && !isNaN(offsetNumber)) {
const color = Color(stopColor).alpha(extractOpacity(stopOpacity)).rgb().array();
const color = Color(stopColor)
.alpha(extractOpacity(stopOpacity))
.rgb()
.array();
const r = color[0] / 255;
const g = color[1] / 255;
const b = color[2] / 255;
@@ -58,8 +71,11 @@ export default function extractGradient(props) {
return {
name: id,
children: childArray,
gradient: colors.concat(offsets),
gradientUnits: units[gradientUnits] || 0,
gradientTransform: extractTransform(gradientTransform || transform || props),
gradientTransform: extractTransform(
gradientTransform || transform || props,
),
};
}