react-native-reanimated: Transition API not working on Android

Hey, so I was really impressed by the new Transition API’s ease of use and immediately tried it out, but it just won’t work on Android for me. On iOS it works just fine, but on Android, it won’t animate anything.

I have the following function (which is basically a straight copy of the progress.js example):

import React, { useState, useRef } from "react";
import { View, StyleSheet } from "react-native";
import { Transitioning, Transition } from "react-native-reanimated";

import { Button } from "common";

export default function TestScreen() {
  const transition = <Transition.Change interpolation="easeInOut" durationMs={600} />;

  let [perc, setPerc] = useState(20);
  const ref = useRef();

  return (
    <Transitioning.View ref={ref} transition={transition} style={styles.centerAll}>
      <Button
        activeOpacity={0.2}
        onPress={() => {
          ref.current.animateNextTransition();
          setPerc(perc + 20 <= 100 ? perc + 20 : 20);
        }}
        style={{ borderRadius: 0 }}
        viewStyle={styles.accordionButtonStyle}
      >
        {perc + 20 <= 100 ? "+20%" : "-80%"}
      </Button>
      <View style={styles.bar}>
        <View style={{ height: 5, width: `${perc}%`, backgroundColor: "#FF5252" }} />
      </View>
    </Transitioning.View>
  );
}

const styles = StyleSheet.create({
  accordionButtonStyle: {
    shadowColor: "black",
    shadowOffset: { width: 0, height: 0 },
    shadowOpacity: 0.2,
    shadowRadius: 3
  },
  centerAll: {
    flex: 1,
    alignItems: "center",
    marginTop: 100
  },
  bar: {
    marginTop: 30,
    height: 5,
    width: "80%",
    backgroundColor: "#AAA"
  }
});

I simply import this to my StackNavigator like this:

import { createStackNavigator } from "react-navigation";

import HomeScreen from "tabs/main/home/HomeScreen";
import ArticleScreen from "tabs/main/article/ArticleScreen";
import TestScreen from "tabs/main/test/TestScreen";
import { nav } from "static/constants";

export const MainStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen,
      navigationOptions: {
        title: "Home"
      }
    },
    Article: {
      screen: ArticleScreen
    },
    Test: {
      screen: TestScreen,
      navigationOptions: {
        title: "Testing Area"
      }
    }
  },
  {
    initialRouteName: nav.HOME
  }
);

I have two screen caps that illustrate the behavior: screenCap_Android

screencap_iOS

Here is some other data that may be important:

React version: 16.8.6
React Native version: 0.59.8
Android API Level: 28
Reanimated version: 1.0.1

Am I missing something really obvious here? Maybe someone can help me. Thanks in advance!

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 35 (3 by maintainers)

Most upvoted comments

Okay, I have an even more minimal reproduction. In my environment, I had react-native-screens installed but disabled because of an unrelated issue. I noticed that the transitions would work in some contexts if I re-enabled screens.

When screens are disabled, react-navigation’s TabNavigator wraps tabs in a View with removeClippedSubviews enabled. See https://github.com/react-navigation/tabs/blob/44b895fa114465fedafba217c27a2918ed38367d/src/views/ResourceSavingScene.js#L35

If I rip all of the navigation stuff out and similarly wrap the progress example in a view with removeClippedSubviews enabled, then transitions stop working.

import React, { useState, useRef } from 'react';
import { View, StyleSheet, Button } from 'react-native';
import { Transitioning, Transition } from 'react-native-reanimated';

export default function Progress() {
  const transition = <Transition.Change interpolation="easeInOut" />;

  let [perc, setPerc] = useState(20);
  const ref = useRef();

  // Transitions will not work on Android with removeClippedSubviews. If you set
  // this to false, transitions will work.
  return (
    <View removeClippedSubviews style={{ flex: 1 }}>
      <Transitioning.View
          ref={ref}
          style={styles.centerAll}
          transition={transition}>
        <Button
            title={perc + 20 <= 100 ? '+20%' : '-80%'}
            color="#FF5252"
            onPress={() => {
              ref.current.animateNextTransition();
              setPerc(perc + 20 <= 100 ? perc + 20 : 20);
            }}
        />
        <View style={styles.bar}>
          <View
            style={{ height: 5, width: `${perc}%`, backgroundColor: '#FF5252' }}
          />
        </View>
      </Transitioning.View>
    </View>
  );
}

const styles = StyleSheet.create({
  centerAll: {
    flex: 1,
    alignItems: 'center',
    marginTop: 100,
  },
  bar: {
    marginTop: 30,
    height: 5,
    width: '80%',
    backgroundColor: '#aaa',
  },
});

@mralj, can you check your render tree for any views along the way with removeClippedSubviews enabled? I searched the react-native-navigation repo for removeClippedSubviews but didn’t get any hits. There might be other causes here.

I have this code and this issue persist, some update?

export default function App() {
  const progress = useSharedValue(1)
  const scale = useSharedValue(1)

  const reanimatedStyle = useAnimatedStyle(() => {
    return {
      opacity: progress.value,
      transform: [{ scale: scale.value }],
    }
  }, [])

  useEffect(() => {
    progress.value = withTiming(0.9, { duration: 5000 })
    scale.value = withTiming(2)
  }, [])

  return (
    <View style={styles.container}>
      <StatusBar style="auto" />

      <Animated.View
        style={[
          {
            width: SIZE,
            height: SIZE,
            backgroundColor: 'blue',
            borderRadius: BORDER_RADIUS,
          },
          reanimatedStyle,
        ]}
      />
    </View>
  )
}
"react-native": "0.69.5",
"react-native-reanimated": "~2.9.1",
plugins: ['react-native-reanimated/plugin'],

🚨 I opened the app in the emulator and it worked, it just doesn’t work on the physical device.

I don’t know the versions of reanimated, and screens used in expo, but it’s not the newest versions. It’s resolved on newest versions : https://github.com/software-mansion/react-native-screens/issues/203#issuecomment-640917824

I’m using react-navigation 5 and rn-screens and transition animations not working on android sometimes I change some view settings and it starts to work after fast-refresh but when I reload the app it doesn’t work anymore. disabling the enableScreens won’t help.

Based on the tree posted by @mralj, my suspicion is that there are multiple causes at work here. removeClippedSubviews is just one of them.

Edit: Wait, are you saying that it doesn’t work when RNScreens is disabled? Because I have screens enabled and it doesn’t work. I’m a bit confused by your comment up top

When react-native-screens is enabled (it is installed and you’ve called useScreens()), removeClippedSubviews={true} is not used by react-navigation’s tabbed navigators. Transitions should work under those conditions unless something else is breaking them. Using the first minimal reproduction that I posted, you should be able to duplicate this behavior by adding useScreens() to get the transitions to work and removing useScreens() to cause them to break again.

@Mazzel-13, if you’re using a tabbed navigator and screens, transitions should be working unless something else is using removeClippedSubviews higher up in your tree (or there is another root cause at play). Note that you can’t simply add a View with removeClippedSubviews={false} to work around this. If a View higher up in three has it enabled, transitions won’t work.

FWIW, after getting Transitions to work in my app, I found them to be largely unusable on Android (https://github.com/kmagiera/react-native-reanimated/issues/257#issuecomment-487119010 was just one issue I encountered almost immediately). While I do think it’s worth helping to track down the cause of issues like the one we’re discussing, I wouldn’t recommend investing heavily here because you’re anticipating being able to use reanimated in a production context immediately. It seems we need to help it mature a bit first.