-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Changing style values from regular to Animated.Value removes view for several frames #219
Comments
@terrysahaidak Did you ever find the cause of this issue in the Android source code? I'm struggling with the same issue... |
Ok - is @ddzirt listening in here? Would be great to try to work together to find a solution. |
@chrfalch Yes, I am investigating this when I am relatively free. From initial investigation - the issue is that view is recreated when animation starts. |
Thanks for reaching out, @ddzirt :) Yes, that is also what I've seen. Switching style from a regular style to an animated style causes the view to be recreated. This is very visible on Android, but it is also looks like this is can be seen on iOS in some circumstances. Any idea what causes this view recreation? |
I went through node creation, and I think that Animated.Value is not used for the view before animation is actually triggered. Regarding iOS I think there is the same issue, since I saw the same thing when I tried using new feature on iOS. But I saw that two days ago and had no time yet to confirm it in isolated project instead of work project |
Have you been able to identify the area in the source code that causes this recreation? |
Unfortunately not yet New feature that gave me the same bug was Transition. I used the same code as in example |
I asked @osdnk about this as well. Hopefully we can find some kind of solution to this. Feel free to shout out if you want me to investigate or test out something. I'm currently working on a big rewrite of Fluid Transitions that uses Reanimated and this is what stops me at the moment. |
I am in a need as well, so I'll be investigating more and if I'll find something there will be more posts |
Ok, please don't hesitate contacting me if you find something. |
I've investigated this issue and I think I have found the problem. First of all - this is NOT an Android problem - this is happens on iOS as well (change title, @terrysahaidak ?), it just happens so quickly that it is hard to see it :) The problem is evident if you attach a spy function to the message queue and is mostly visible for width/height/flex style properties (or style properties that forces a layout update). The view is not recreated as we first assumed. The issue is that when you update the styles the view will receive a call to update its properties through the I'm investigating the possibilities for a fix and will come back :) |
@chrfalch nice, this at least gives us a proper understanding of what is happening |
The problem seems to come from the createAnimatedComponent function's render method where animated nodes are removed from the style - which in turn causes React Native to emit a call to UIManager updateView with a null value for the width/height/flex value - ending up with a size equal to zero when recalculating sizes. The update from Reanimated arrives a little bit later, causing the view to flicker like it was removed for a frame or two. |
@chrfalch I think we could try to investigate how original Animated with useNativeDriver works. At least that is my initial plan on trying to fix this. |
@ddzirt Another solution would be to take over all animatable properties and styles and not separate those that have animated nodes from those that doesn’t. This way reanimated would have full control over updating props on views without the synchronization issue. I’m have made a simple test doing this and it seems to be working fine. |
@chrfalch does it impact performance, by any chance? Especially if entire screen is fully covered by animations? I mean the loading/initialization time needed for reanimated to kick in. And if you have an example it would be great if you could share |
I'm traveling today so I won't be able to share anything - will try to see if I can get something together in the next few days. Don't think it will affect performance, what I'm suggesting is only to change updating props to "all from reanimated" instead of "some from react native, some from reanimated". |
No worries, I have free time only on weekends to play around the code, so I can wait. About performance - it is just to be sure :) |
I've added a simple solution where I remove style from props in the Animated component. All styles for a component are transferred through an AnimatedStyle node - not just the style containing animated values. The patch works on iOS - haven't got the time to fix it for Android, but a similar fix as the one I've done to the REAStyleNode.m should be implemented in the StyleNode.java (and utils.processMapping). The only drawback I have found is that the component will be drawn once by React Native without styles before Reanimated applies styles. This should be fixable. Here is my patch:
|
Is there any updates on this? This is still an issue and makes impossible to have any components that have any animated initial state along side with regular styling. |
Can you guys check if #1027 fixes that issue for you? |
## Description Fixes #219 Fixes #762 Previously components were flickering when mounted due to asynchronously updating component styles. In `createAnimatedComponent()` we filtered out styles with Animated nodes, then component rendered with default values, then nodes were initialized on the native side and applied their styles. This issue was mostly observed when layout styles were changed, for example when setting height like in the example below. This fix relies on updating the value of `Value` when nodes are detached (`__detach()` in `InternalAnimatedValue`) because it updates its value on the JS side. Without that this fix would only work on the first mount (when initial values are used). ## Example ```js import * as React from 'react'; import {Button, Text, View} from 'react-native'; import Animated from 'react-native-reanimated'; export default function Flickering() { const value = Animated.useValue(80); const [i, setI] = React.useState(0); const triggerRemount = () => { setI(i => i + 1); }; return ( <View key={i} style={{ height: '100%', backgroundColor: 'white', position: 'relative', paddingTop: 100, }}> <Animated.View style={{ height: value, position: 'absolute', width: '100%', backgroundColor: 'green', }}> <Text style={{color: 'white', fontSize: 15}}>Some footer</Text> </Animated.View> <Button onPress={() => { triggerRemount(); }} style={{marginTop: 100}} title="Trigger remount!" /> </View> ); } ```
Fixes #219 Fixes #762 Previously components were flickering when mounted due to asynchronously updating component styles. In `createAnimatedComponent()` we filtered out styles with Animated nodes, then component rendered with default values, then nodes were initialized on the native side and applied their styles. This issue was mostly observed when layout styles were changed, for example when setting height like in the example below. This fix relies on updating the value of `Value` when nodes are detached (`__detach()` in `InternalAnimatedValue`) because it updates its value on the JS side. Without that this fix would only work on the first mount (when initial values are used). It also doesn't support any nested properties (like transform). ```js import * as React from 'react'; import {Button, Text, View} from 'react-native'; import Animated from 'react-native-reanimated'; export default function Flickering() { const value = Animated.useValue(80); const [i, setI] = React.useState(0); const triggerRemount = () => { setI(i => i + 1); }; return ( <View key={i} style={{ height: '100%', backgroundColor: 'white', position: 'relative', paddingTop: 100, }}> <Animated.View style={{ height: value, position: 'absolute', width: '100%', backgroundColor: 'green', }}> <Text style={{color: 'white', fontSize: 15}}>Some footer</Text> </Animated.View> <Button onPress={() => { triggerRemount(); }} style={{marginTop: 100}} title="Trigger remount!" /> </View> ); } ```
Fixes #219 Fixes #762 Previously components were flickering when mounted due to asynchronously updating component styles. In `createAnimatedComponent()` we filtered out styles with Animated nodes, then component rendered with default values, then nodes were initialized on the native side and applied their styles. This issue was mostly observed when layout styles were changed, for example when setting height like in the example below. This fix relies on updating the value of `Value` when nodes are detached (`__detach()` in `InternalAnimatedValue`) because it updates its value on the JS side. Without that this fix would only work on the first mount (when initial values are used). It also doesn't support any nested properties (like transform). ```js import * as React from 'react'; import {Button, Text, View} from 'react-native'; import Animated from 'react-native-reanimated'; export default function Flickering() { const value = Animated.useValue(80); const [i, setI] = React.useState(0); const triggerRemount = () => { setI(i => i + 1); }; return ( <View key={i} style={{ height: '100%', backgroundColor: 'white', position: 'relative', paddingTop: 100, }}> <Animated.View style={{ height: value, position: 'absolute', width: '100%', backgroundColor: 'green', }}> <Text style={{color: 'white', fontSize: 15}}>Some footer</Text> </Animated.View> <Button onPress={() => { triggerRemount(); }} style={{marginTop: 100}} title="Trigger remount!" /> </View> ); } ```
Description
If you have an
Animated.View
with regularwidth: 100
style values and want to change it to anAnimated.Value
instancewidth: new Animated.Value(100)
, it removes the view completely from view hierarchy for several frames and mounts again.Reproducing example
https://snack.expo.io/@terrysahaidak/reanimated-removes-view-bug
Video
https://drive.google.com/file/d/1HIfFt9vWX23lcnZukQSlw1n15-1ZWzcw/view?usp=drivesdk
Explanation
Why you ever want to change some values from animated one to regular?
The case I was playing with is lazy value initializations.
Since creating a lot of
Animated.Value
blocks the js thread (see #194) and I have a lot of them on the same screen, I do not initialize them until I start the animation by some event (for example, pressing the button or focusing the input).The text was updated successfully, but these errors were encountered: