React-native-reanimated: [v2] rotate transform (withTiming) exception on Android

Created on 3 Aug 2020  路  13Comments  路  Source: software-mansion/react-native-reanimated

Description

The following snippet throws an exception on Android but works on iOS.

Exception: Invariant Violation: Transform with key of "rotateZ" must be a string: {"rotateZ":0}
Adding deg or rad to the string just crashes the app instead.

const animatedStyle = useAnimatedStyle(() => {
    const toValue = isOpen.value ? Math.PI / 4 : 0;
    const rotateZ = withTiming(toValue, {
      duration: 100,
      easing: Easing.linear,
    });

    return {
      transform: [
        {
          rotateZ,
        },
      ],
    };
});

Screenshots

image

Steps To Reproduce

use any of the rotate transforms on Android and apply withTiming

Package versions

  • React: 16.13.1
  • React Native: 0.63.2
  • React Native Reanimated: 2.0.0-alpha.4

Logcat

 Error while updating prop transform
    java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:87)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:136)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:56)
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:49)
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:137)
        at com.facebook.react.uimanager.UIImplementation.synchronouslyUpdateViewOnUIThread(UIImplementation.java:291)
        at com.swmansion.reanimated.NodesManager.updateProps(NodesManager.java:473)
        at com.swmansion.reanimated.NativeProxy.updateProps(NativeProxy.java:91)
        at com.swmansion.reanimated.NativeProxy$AnimationFrameCallback.onAnimationFrame(Native Method)
        at com.swmansion.reanimated.NodesManager.onAnimationFrame(NodesManager.java:174)
        at com.swmansion.reanimated.NodesManager.access$000(NodesManager.java:61)
        at com.swmansion.reanimated.NodesManager$1.doFrameGuarded(NodesManager.java:127)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:175)
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:85)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:947)
        at android.view.Choreographer.doCallbacks(Choreographer.java:761)
        at android.view.Choreographer.doFrame(Choreographer.java:693)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.NumberFormatException: For input string: "[object Object]"
        at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
        at sun.misc.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
        at java.lang.Float.parseFloat(Float.java:451)
        at com.facebook.react.uimanager.TransformHelper.convertToRadians(TransformHelper.java:40)
        at com.facebook.react.uimanager.TransformHelper.processTransform(TransformHelper.java:68)
        at com.facebook.react.uimanager.BaseViewManager.setTransformProperty(BaseViewManager.java:322)
        at com.facebook.react.uimanager.BaseViewManager.setTransform(BaseViewManager.java:82)
        at com.facebook.react.views.view.ReactViewManager.setTransform(ReactViewManager.java:272)
        at com.facebook.react.views.view.ReactViewManager.setTransform(ReactViewManager.java:37)
        at java.lang.reflect.Method.invoke(Native Method)聽
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:87)聽
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:136)聽
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:56)聽
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:49)聽
        at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:137)聽
        at com.facebook.react.uimanager.UIImplementation.synchronouslyUpdateViewOnUIThread(UIImplementation.java:291)聽
        at com.swmansion.reanimated.NodesManager.updateProps(NodesManager.java:473)聽
        at com.swmansion.reanimated.NativeProxy.updateProps(NativeProxy.java:91)聽
        at com.swmansion.reanimated.NativeProxy$AnimationFrameCallback.onAnimationFrame(Native Method)聽
        at com.swmansion.reanimated.NodesManager.onAnimationFrame(NodesManager.java:174)聽
        at com.swmansion.reanimated.NodesManager.access$000(NodesManager.java:61)聽
        at com.swmansion.reanimated.NodesManager$1.doFrameGuarded(NodesManager.java:127)聽
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)聽
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:175)聽
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:85)聽
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:947)聽
        at android.view.Choreographer.doCallbacks(Choreographer.java:761)聽
        at android.view.Choreographer.doFrame(Choreographer.java:693)聽
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)聽
        at android.os.Handler.handleCallback(Handler.java:873)聽
        at android.os.Handler.dispatchMessage(Handler.java:99)聽
        at android.os.Looper.loop(Looper.java:193)聽
        at android.app.ActivityThread.main(ActivityThread.java:6669)聽
        at java.lang.reflect.Method.invoke(Native Method)聽
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)聽
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)聽

馃彔 Reanimated2 馃悶 Bug 馃android

All 13 comments

Alongside all other rotate transforms: rotate, rotateX & rotateY

Okay, it seems the withTiming is what breaks it on Android.

I'm able to do the following without any issues

  • rotateZ: '${toValue}deg' //changed quotes so it shows on GH
  • rotateZ: '100deg'
  • rotateZ: '100rad'

I think on Android it expects it to be a number so without "deg"

Hey @terrysahaidak, when I pass just a number it fails too (saying it expects deg or rad). My comment above shows that it works when not using withTiming but fails as soon as you use it.

Oh sorry, missed it in the description.

So seems like I was wrong and Android expects string but we cannot run withTiming with string values.

/cc @kmagiera @Szymon20000

@terrysahaidak FWIW with the latest alpha.5, withTiming no longer works with any transform props (on both iOS and Android)

could you create reproducing repo for rotate as well as other issues you have right now?

So it seems a TypeScript error is causing withTiming to not work with a user config (Easing is missing from the types), once ignoring this, then withTiming works fine however not on transform props (as mentioned above).

Repro for android (

import React from 'react';
import {View, Button} from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
  Easing,
} from 'react-native-reanimated';

interface Props {}

export function Repro({}: Props) {
  const isOpen = useSharedValue(false);
  const onPress = React.useCallback(() => {
    isOpen.value = !isOpen.value;
  }, [isOpen]);

  const animatedStyle = useAnimatedStyle(() => {
    const toValue = isOpen.value ? 100 : 0;
    const timing = withTiming(toValue, {duration: 1000, easing: Easing.linear});

    return {
      transform: [
        {
          rotate: `${toValue}deg`, // deg required for android
          //rotate: timing, // this works for iOS not Android
        },
      ],
    };
  });

  return (
    <View style={{justifyContent: 'center', alignItems: 'center'}}>
      <Animated.View
        style={[
          {width: 100, height: 100, backgroundColor: 'red'},
          animatedStyle,
        ]}
      />
      <Button onPress={onPress} title="Toggle rotation" />
    </View>
  );
}

Okay, so I think my usage is somewhat wrong (even though it works on iOS).

This works on both platforms

```typescript
const rotateZ = useDerivedValue(() => {
return withTiming(isOpen.value ? 45 : 0, {
duration: 100,
easing: Easing.linear,
});
});

const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{rotateZ: ${rotateZ.value}deg}],
};
});
```

Code snippets are good, but it's way better to provide reproducing repository instead. With the repository, we can make sure our setup and versions of everything are the same.

@terrysahaidak I'm facing the same issue with the last version of Reanimated 2.0.0-alpha.9.2.

When I set it to rotate as a string the error is gone (Android) but it's not rotated, Also iOS not rotated however if it's Number Rotation work just in iOS.

Here's the Repo you can check it if u wondering.

I'm facing the same issue trying to make some rotation in rotateZ property.

Sample

    const starStyle = useAnimatedStyle(() => {
        const scaleArray = [
            withDelay(index * (delay / 2), withTiming(scale.value, { duration: 500, easing: Easing.bounce })),
            withDelay(500, withTiming(1, { duration: 500, easing: Easing.ease })),
        ];

        const rotateArray = [
            withDelay(index * (delay / 2), withTiming(0, { duration: 500, easing: Easing.ease })),
            withDelay(500, withTiming(rotate.value, { duration: 500, easing: Easing.ease })),
        ];

        if (index > rate) {
            scaleArray.shift();
            rotateArray.shift();
        } else if (rate === index) {
            scaleArray.pop();
            rotateArray.pop();
        }

        const opacityDelay = withDelay(index * (delay / 2), withTiming(opacity.value, { duration: 250 }));
        const rotateSequence = withSequence(...rotateArray);
        const scaleSequence = withSequence(...scaleArray);

        return {
            opacity: opacityDelay,
            transform: [
                { rotateZ: rotateSequence },
                {
                    scale: scaleSequence,
                },
            ],
        };
    }, [index, rate]);

EDIT: if wrapping in a string it crashes the app.

any progress on this?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robertgonzales picture robertgonzales  路  3Comments

colinux picture colinux  路  3Comments

jwhscholten picture jwhscholten  路  4Comments

levibuzolic picture levibuzolic  路  3Comments

ShaMan123 picture ShaMan123  路  3Comments