-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add possibility to start layout animation when entering one hasn't fi…
…nished (#2135) Fixes: #2119 When we get notified by ReactBatchObserver about the dirtiness of a component then we have to choose how should we animate that layout change. For instance, we have to decide if it should be entering, layout, or exiting animation. Each component is treated as a state machine with the following lifecycle: inactive -> appearing -> layout -> disappearing -> toRemove Currently, we do not start a layout animation if the component is still entering. The problem with that is sometimes the coordinates of the component can change and our component will not be rendered properly. You can read more about it in the issue linked above. The solution for that is simply to start a layout animation when the component is dirty. The problem with that solution is the sometimes component can be dirty which doesn't mean that the layout of the component has changed. For instance, the component can be marked dirty because one of its descendants had changed its layout. To fix the solution I also added check if the startingValues (layout snapshot took as the first operation of UIManager's UI queue operations) are the same as targetValues ((layout snapshot took as the last operation of UIManager's UI queue operations). If they are it means that there was no UI operation that changed the layout of the component and it means that the dirtiness of the component is a false positive. I also added 3 examples that helped me test this pull-request.
- Loading branch information
Szymon20000
committed
Jun 17, 2021
1 parent
1a6b2fb
commit 4d85ca1
Showing
9 changed files
with
341 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { selectAssetSource } from 'expo-asset/build/AssetSources'; | ||
import React, { useState } from 'react'; | ||
import { View, Text, Button, StyleSheet } from 'react-native'; | ||
import Animated, { | ||
AnimatedLayout, | ||
makeMutable, | ||
withTiming, | ||
withDelay, | ||
SlideInDown, | ||
} from 'react-native-reanimated'; | ||
|
||
function CustomLayoutTransiton() { | ||
const isEven = makeMutable(1); | ||
return (values) => { | ||
'worklet'; | ||
const isEvenLocal = isEven.value; | ||
isEven.value = 1 - isEven.value; | ||
|
||
return { | ||
animations: { | ||
originX: withDelay( | ||
isEvenLocal ? 1000 : 0, | ||
withTiming(values.originX, { duration: 1000 }) | ||
), | ||
originY: withDelay( | ||
isEvenLocal ? 0 : 1000, | ||
withTiming(values.originY, { duration: 1000 }) | ||
), | ||
width: withTiming(values.width, { duration: 1000 }), | ||
height: withTiming(values.height, { duration: 1000 }), | ||
}, | ||
initialValues: { | ||
originX: values.boriginX, | ||
originY: values.boriginY, | ||
width: values.bwidth, | ||
height: values.bheight, | ||
}, | ||
}; | ||
}; | ||
} | ||
|
||
function Box({ label, state }: { label: string; state: boolean }) { | ||
const ind = label.charCodeAt(0) - 'A'.charCodeAt(0); | ||
const delay = 300 * ind; | ||
return ( | ||
<Animated.View | ||
layout={CustomLayoutTransiton()} | ||
style={[styles.box, { height: state ? 30 : 60 }]}> | ||
<Text> {label} </Text> | ||
</Animated.View> | ||
); | ||
} | ||
|
||
export function CustomLayoutAnimationScreen(): React.ReactElement { | ||
const [state, setState] = useState(true); | ||
return ( | ||
<View style={{ marginTop: 30 }}> | ||
<View style={{ height: 300 }}> | ||
<AnimatedLayout | ||
style={{ flexDirection: state ? 'row' : 'column', borderWidth: 1 }}> | ||
<Box key="a" label="A" state={state} /> | ||
<Box key="b" label="B" state={state} /> | ||
<Box key="c" label="C" state={state} /> | ||
</AnimatedLayout> | ||
</View> | ||
|
||
<Button | ||
onPress={() => { | ||
setState(!state); | ||
}} | ||
title="toggle" | ||
/> | ||
</View> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
box: { | ||
margin: 20, | ||
padding: 5, | ||
borderWidth: 1, | ||
borderColor: 'black', | ||
width: 60, | ||
height: 60, | ||
}, | ||
}); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { selectAssetSource } from 'expo-asset/build/AssetSources'; | ||
import React, { useState } from 'react'; | ||
import { View, Text, Button, StyleSheet } from 'react-native'; | ||
import Animated, { | ||
AnimatedLayout, | ||
makeMutable, | ||
withTiming, | ||
withDelay, | ||
SlideInDown, | ||
} from 'react-native-reanimated'; | ||
|
||
function CustomLayoutTransiton() { | ||
const isEven = makeMutable(1); | ||
return (values) => { | ||
'worklet'; | ||
const isEvenLocal = isEven.value; | ||
isEven.value = 1 - isEven.value; | ||
|
||
return { | ||
animations: { | ||
originX: withDelay( | ||
isEvenLocal ? 1000 : 0, | ||
withTiming(values.originX, { duration: 1000 }) | ||
), | ||
originY: withDelay( | ||
isEvenLocal ? 0 : 1000, | ||
withTiming(values.originY, { duration: 1000 }) | ||
), | ||
width: withTiming(values.width, { duration: 1000 }), | ||
height: withTiming(values.height, { duration: 1000 }), | ||
}, | ||
initialValues: { | ||
originX: values.boriginX, | ||
originY: values.boriginY, | ||
width: values.bwidth, | ||
height: values.bheight, | ||
}, | ||
}; | ||
}; | ||
} | ||
|
||
function Box({ label, state }: { label: string; state: boolean }) { | ||
const ind = label.charCodeAt(0) - 'A'.charCodeAt(0); | ||
const delay = 300 * ind; | ||
return ( | ||
<Animated.View | ||
layout={CustomLayoutTransiton()} | ||
entering={SlideInDown.delay(delay).duration(3000)} | ||
style={[styles.box, { height: state ? 30 : 60 }]}> | ||
<Text> {label} </Text> | ||
</Animated.View> | ||
); | ||
} | ||
|
||
export function CustomLayoutAnimationScreen2(): React.ReactElement { | ||
const [state, setState] = useState(true); | ||
return ( | ||
<View style={{ marginTop: 30 }}> | ||
<View style={{ height: 300 }}> | ||
<AnimatedLayout | ||
style={{ flexDirection: state ? 'row' : 'column', borderWidth: 1 }}> | ||
<Box key="a" label="A" state={state} /> | ||
<Box key="b" label="B" state={state} /> | ||
<Box key="c" label="C" state={state} /> | ||
</AnimatedLayout> | ||
</View> | ||
|
||
<Button | ||
onPress={() => { | ||
setState(!state); | ||
}} | ||
title="toggle" | ||
/> | ||
</View> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
box: { | ||
margin: 20, | ||
padding: 5, | ||
borderWidth: 1, | ||
borderColor: 'black', | ||
width: 60, | ||
height: 60, | ||
}, | ||
}); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { selectAssetSource } from 'expo-asset/build/AssetSources'; | ||
import React, { useState } from 'react'; | ||
import { View, Text, Button, StyleSheet } from 'react-native'; | ||
import Animated, { | ||
AnimatedLayout, | ||
makeMutable, | ||
withTiming, | ||
withDelay, | ||
SlideInDown, | ||
} from 'react-native-reanimated'; | ||
|
||
function CustomLayoutTransiton() { | ||
const isEven = makeMutable(1); | ||
return (values) => { | ||
'worklet'; | ||
const isEvenLocal = isEven.value; | ||
isEven.value = 1 - isEven.value; | ||
|
||
return { | ||
animations: { | ||
originX: withDelay( | ||
isEvenLocal ? 1000 : 0, | ||
withTiming(values.originX, { duration: 1000 }) | ||
), | ||
originY: withDelay( | ||
isEvenLocal ? 0 : 1000, | ||
withTiming(values.originY, { duration: 1000 }) | ||
), | ||
width: withTiming(values.width, { duration: 1000 }), | ||
height: withTiming(values.height, { duration: 1000 }), | ||
}, | ||
initialValues: { | ||
originX: values.boriginX, | ||
originY: values.boriginY, | ||
width: values.bwidth, | ||
height: values.bheight, | ||
}, | ||
}; | ||
}; | ||
} | ||
|
||
function Box({ label, state }: { label: string; state: boolean }) { | ||
const ind = label.charCodeAt(0) - 'A'.charCodeAt(0); | ||
const delay = 300 * ind; | ||
return ( | ||
<Animated.View | ||
layout={CustomLayoutTransiton()} | ||
entering={SlideInDown.delay(delay).duration(3000)} | ||
style={[styles.box, { flexDirection: state ? 'row': 'row-reverse' }]}> | ||
<Text> {label} </Text> | ||
</Animated.View> | ||
); | ||
} | ||
|
||
export function CustomLayoutAnimationScreen3(): React.ReactElement { | ||
const [state, setState] = useState(true); | ||
return ( | ||
<View style={{ marginTop: 30 }}> | ||
<View style={{ height: 300 }}> | ||
<AnimatedLayout | ||
style={{ flexDirection: 'row', borderWidth: 1 }}> | ||
<Box key="a" label="A" state={state} /> | ||
<Box key="b" label="B" state={state} /> | ||
<Box key="c" label="C" state={state} /> | ||
</AnimatedLayout> | ||
</View> | ||
|
||
<Button | ||
onPress={() => { | ||
setState(!state); | ||
}} | ||
title="toggle" | ||
/> | ||
</View> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
box: { | ||
margin: 20, | ||
padding: 5, | ||
borderWidth: 1, | ||
borderColor: 'black', | ||
width: 60, | ||
height: 60, | ||
}, | ||
}); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.