Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple animations with useAnimatedStyle flicker on Fabric #6865

Closed
thiagobrez opened this issue Jan 3, 2025 · 10 comments
Closed

Simple animations with useAnimatedStyle flicker on Fabric #6865

thiagobrez opened this issue Jan 3, 2025 · 10 comments
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@thiagobrez
Copy link

Description

Simple animations such as animating the height of a component with useAnimatedStyles and withSpring flicker on New Architecture with Fabric.

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-01-03.at.15.50.14.mp4

Steps to reproduce

  1. Create a shared value: const height = useSharedValue<number>(0);
  2. Create an animated style: const animatedStyles = useAnimatedStyle(() => ({ height: height.value }));
  3. Create a function to animate: const onToggleHeight = () => { height.value = withSpring(height.value > 0 ? 0 : 200) };
  4. Apply the animated style to a view: <Animated.View style={animatedStyles} />
  5. The animation seems to always flicker when animating to height: 0 in this case. I've also seen it happen when animating to opacity: 0 in other cases

Snack or a link to a repository

/~https://github.com/thiagobrez/reanimated-repro

Reanimated version

3.16.6

React Native version

0.76.5

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Fabric (New Architecture)

Build type

Debug app & dev bundle

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided labels Jan 3, 2025
@danieljvdm
Copy link

I recently reported this issue in react-navigation but I suspect it's closely related to this issue. useAnimatedStyle seems to be causing a lot of random flickers across unrelated components for me.

react-navigation/react-navigation#12410

@fendermany
Copy link

I notice there are all sorts of bugs when used reanimated on the new architecture include this

@fendermany
Copy link

This is also true for useDerivedValue

@mhoran
Copy link
Contributor

mhoran commented Feb 17, 2025

A similar issue was reported for Android (#6854) and I believe the issues likely have the same root cause (see #6776). The state between Reanimated and React Native seems to get out of sync, causing animations to jump between what Reanimated thinks the value should be and what React Native thinks the value should be.

I had thought the issue may be related to a render from the React Native side coinciding with the animation (e.g. prop change). But your simple example does not trigger a render -- the height is only being changed by Reanimated. That would seem to suggest that something else may be happening.

I see similar issues in my app when using react-native-drawer-layout. The layout sometimes jumps between positions when the drawer is opening or closing. react-native-drawer-layout is also using withSpring, so perhaps that's where the issue is coming from. Regardless, the main issue seems to be that the animated value seems to get out of sync and jumps between values.

(Note: react-native-drawer-layout sets overshootClamping: true, which if set in your example, resolves the performance issue. So there may still be another issue at play here.)

@thiagobrez
Copy link
Author

Thanks for the context @mhoran! And yeah, I've been following both issues you linked, and also thought they were somehow related. I also have the patch from #6776 applied locally to fix Modal behaviors for now.

I found this issue when trying to upgrade an app to RN 0.76 with New Arch, and a few other issues related to navigation flickering / screens jumping around, but those I failed to reproduce in a fresh new app unfortunately.

Thanks for the tip on overshootClamping, I was not aware and will try as a workaround!

@mhoran
Copy link
Contributor

mhoran commented Feb 17, 2025

It seems that with a longer duration set, withSpring will still jump even when overshootClamping: true is set. The default duration must be short enough to effectively null out the bounce when overshootClamping: true is set -- but it doesn't fix the underlying issue.

I'm trying to isolate the issue I'm seeing with (animated) props as it seems related, but it's incredibly hard to test outside of a fully integrated app. I'm hoping all these issues will be fixed once the commit hook issue is resolved, but having dedicated repros would make it easier for the Reanimated team.

@danieljvdm
Copy link

@thiagobrez curious if my repo here reproduces the issue for you: /~https://github.com/danieljvdm/screens-bug. For me I can reproduce issues when presenting screens when there's a screen in the stack that has useAnimatedStyle

@bartlomiejbloniarz
Copy link
Contributor

@thiagobrez

The issue here isn't really performance related. You are animating the height using withSpring, with toValue=0. This will cause the height to go negative. When height is negative, RN will treat it as if it wasn't defined. So it will make the red component's height equal to the height of its children.

There isn't really anything we can do with that on our side. You can use withClamp to bound the shared value:

height.value = withClamp(
      { min: 0 },
      withSpring(height.value > 0 ? 0 : 200)
    );

alternatively, you could use, but this would look less "springy":

height.value = withSpring(height.value > 0 ? 0 : 200, {
      clamp: { min: 0 },
    });

@mhoran
Copy link
Contributor

mhoran commented Feb 20, 2025

@bartlomiejbloniarz should withClamp behave differently than overshootClamping: true? I am able to reproduce the flicker with a long enough duration (e.g. 5s) and overshootClamping: true. This seems to be similar to an issue I see with react-native-drawer-layout. Edit: using withClamp instead of overshootClamping: true seems to work, so the behavior does seem to be different.

As @thiagobrez pointed out, this also seems only to have changed in New Arch, as the behavior is different on Paper. Edit: this does not seem to be the case. Although the animation is a bit smoother on Paper, I see jerkiness when the height goes negative.

@bartlomiejbloniarz
Copy link
Contributor

@mhoran Yes, they do different things. withClamp basically clamps the output value of the wrapped animation. overshootClamping: true stops the animation, when the toValue would be overshot.

Setting duration overrides the overshootClamping value. If you want the animation to automatically figure out when to finish, you shouldn't define duration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

No branches or pull requests

5 participants