software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
8.6k stars 1.26k forks source link

withRepeat is flickering on android #6093

Open MingHieu opened 3 weeks ago

MingHieu commented 3 weeks ago

Description

I'm having a great experience with the animation using withTiming, but when I wrap it with withRepeat, it causes flickering.

Code:

const useMicrophoneAnimation = (isRecording: boolean) => {
  const circleSize = useSharedValue(0);
  const circleOpacity = useSharedValue(0.8);

  const circle1AnimatedStyles = useAnimatedStyle(() => ({
    width: circleSize.value,
    height: circleSize.value,
    opacity: circleOpacity.value,
  }));

  const circle2AnimatedStyles = useAnimatedStyle(() => ({
    width: circleSize.value * 1.4,
    height: circleSize.value * 1.4,
    opacity: circleOpacity.value * 0.9,
  }));

  const circle3AnimatedStyles = useAnimatedStyle(() => ({
    width: circleSize.value * 1.8,
    height: circleSize.value * 1.8,
    opacity: circleOpacity.value * 0.8,
  }));

  useEffect(() => {
    cancelAnimation(circleSize);
    cancelAnimation(circleOpacity);
    circleSize.value = 0;
    circleOpacity.value = 0.8;
    if (isRecording) {
      circleSize.value = withRepeat(withTiming(110, {duration: 1000}), -1);
      circleOpacity.value = withRepeat(withTiming(0, {duration: 1000}), -1);
    }
  }, [isRecording, circleSize, circleOpacity]);

  return {circle1AnimatedStyles, circle2AnimatedStyles, circle3AnimatedStyles};
};
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

<View style={styles.microphoneAnimationWrapper}>
  <AnimatedPressable
    onPress={toggleRecord}
    onPressIn={() => {
      microphoneSize.value = withSpring(0.9);
    }}
    onPressOut={() => {
      microphoneSize.value = withSpring(1);
    }}
    style={[
      styles.microphoneWrapper,
      {
        backgroundColor: color.primary,
        transform: [{scale: microphoneSize}],
      },
    ]}>
    <Image source={require('~assets/images/microphone.png')} />
  </AnimatedPressable>
  <Animated.View
    style={[
      circle1AnimatedStyles,
      styles.microphoneAnimationCircle,
      {backgroundColor: color.primary},
    ]}
  />
  <Animated.View
    style={[
      circle2AnimatedStyles,
      styles.microphoneAnimationCircle,
      {backgroundColor: color.primary},
    ]}
  />
  <Animated.View
    style={[
      circle3AnimatedStyles,
      styles.microphoneAnimationCircle,
      {backgroundColor: color.primary},
    ]}
  />
</View>;

https://github.com/software-mansion/react-native-reanimated/assets/77161145/02bd4094-d951-42f2-8710-f9b651d40390

Steps to reproduce

NA

Snack or a link to a repository

NA

Reanimated version

^3.11.0

React Native version

0.74.1

Platforms

Android

JavaScript runtime

None

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

None

Device

Android emulator

Device model

Pixel_4_API_34 ( android 14 )

Acknowledgements

Yes

github-actions[bot] commented 3 weeks ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

github-actions[bot] commented 3 weeks ago

Hey! 👋

It looks like you've omitted a few important sections from the issue template.

Please complete Steps to reproduce and Snack or a link to a repository sections.

paragbarsar99 commented 2 weeks ago

Are you creating the AnimatedPressable out of component ?

MingHieu commented 2 weeks ago

Are you creating the AnimatedPressable out of component ?

Yes, is anything wrong?

MatiPl01 commented 15 hours ago

Hey! If you encounter this issue, can you try using the following code and let me know if it works?

circleSize.value = withRepeat(
    withSequence(
      withTiming(110, { duration: 1000 }),
      withTiming(0, { duration: 0 })
    ),
    -1
  );
  circleOpacity.value = withRepeat(
    withSequence(
      withTiming(0, { duration: 1000 }),
      withTiming(0.8, { duration: 0 })
    ),
    -1
  );
}

Basically, I add withSequence to the withRepeat, which resets the value to the desired initial value. Duration is set to 0, so the value should retain its initial state immediately.

I was trying to reproduce the issue using the latest reanimated version but I cannot see the problem, even if I was using the same code as provided in this issue repro. Maybe upgrading reanimated to the latest version will help you as well with no need to update the implementation.