Что эквивалентно ротации реагировать-нативно-SVG с происхождением, используя анимированный API-интерфейс - PullRequest
0 голосов
/ 11 января 2020

У меня ниже путь svg, который вращается вокруг начала координат при каждом изменении состояния value, где значение равно значению в несколько градусов:

<Path
   transform={{
      rotation: this.state.value,
      originX: width / 2,
      originY: height / 2
   }}
   d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter 
   fill={Colors.black}
   stroke={Colors.black}
   />

Я вызываю setState для value каждые ~ 20 мс, но это недостаточно плавно, + это не рекомендуемый способ перехода. Чего я хочу добиться, так это анимировать вращение с помощью анимированного API, чтобы добиться более плавного вращения.

Я пытался сделать свое value состояние Animated.Value. Затем создаем Path a Animated.createAnimatedComponent(Path) и вызываем:

Animated.timing(this.state.value, {
    toValue: newDegreesValue,
    duration: 1000,
    useNativeDriver: true
}).start();

Затем я отображаю путь следующим образом:

<Path
   style={transform:[{
      rotate: this.state.value
   }]}
   d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter 
   fill={Colors.black}
   stroke={Colors.black}
   />

Это не работает совсем близко к предыдущему рабочий код с использованием состояния. Одной из причин являются значения originX, originY, которые не поддерживаются API анимации, и я не знаю, как их заменить, но я не уверен, что это единственная причина, может быть, rotate чем-то отличается от свойства rotation ?. Итак, вопрос в том, как достичь того же результата с помощью кода, который непрерывно вызывает setState, используя анимированный API?

Ответы [ 2 ]

0 голосов
/ 25 января 2020

Вот как я этого добился:

// init the animatedComponents
const NeedlePath = Animated.createAnimatedComponent(Path);
const AnimatedG = Animated.createAnimatedComponent(G);

// set the animation
Animated.timing(this.state.angle, {
        toValue: 240, // degrees
        duration: 1000,
        useNativeDriver: true
    }).start();

// pivotX and pivotY are the originX, originY points.
// the width and height are calculated dynamically, so that the whole svg is a square (equal height width), and the center of it are my origins.
render() {
    let height = this.state.height;
    let width = this.state.width;
    let [pivotX, pivotY] = [0, 0];
    if (height && width) {
        [pivotX, pivotY] = [width / 2, height / 2];
    }
   return (
        <View
            style={{ flex: 1}}
            onLayout={event => {
                this.findDimesions(event.nativeEvent.layout); // find height and width dynamically, so that this remain a square container with same height and width
            }}
        >
            {height !== undefined && width !== undefined && (
                <Svg height={height} width={width} style={{ alignItems: "center" }}>
                   <G transform={`translate(${pivotX}, ${pivotY})`}>
                        <AnimatedG
                            style={{
                                transform: [
                                    {
                                        rotate: this.state.angle.interpolate({
                                            inputRange: [0, 360],
                                            outputRange: [`0deg`, `360deg`]
                                        })
                                    }
                                ]
                            }}
                        >
                            <NeedlePath
                                transform={`translate(-${pivotX} -${pivotY})`}
                                d={`M ${width * 0.5} ${height * 0.5} L${width * 0.5 + width * 0.25} ${height * 0.5 + height * 0.25}`}
                                fill={Colors.black}
                                stroke={Colors.black}
                            />
                        </AnimatedG>
                    </G>
                </Svg>
            )}
        </View>
    );
}

style={{ alignItems: "center" }} имеет решающее значение для достижения того же результата и на android, вместо установки translationX и translationY со смещением Android. Это работает для версии v9.13.3 Reaction-native-SVG. Возможно, в более новых версиях это затронуто из-за исправления проблемы с переводами, и я не знаю, какое влияние это окажет на код здесь. Вы можете сослаться на здесь для получения дополнительной информации о переводах со смещением, необходимым на android

0 голосов
/ 11 января 2020

вам нужно использовать интерполяцию


const animation=this.state.value.interpolate({
  inputRange: [0, 360],
  outputRange: ['0deg', '360deg'],
});
<Path
   style={transform:[{
      rotate:animation
   }]}

...