Skip to content

Commit df17439

Browse files
fix: Support for animating only one of boxShadow properties on Android (#8350)
## Summary It's related to the issue mentioned in [this comment](#6687 (comment)). Everything was fine with previous approach when user animated whole `boxShadow` object ```tsx const shadowStyles = useAnimatedStyle(() => { const boxShadow1 = { offset: 0, offsetY: 24, blurRadius: 36, offsetX: 10, spreadDistance: 0, color: 'blue', }; const boxShadow2 = { offsetX: 0, offsetY: 10, blurRadius: 10, spreadDistance: 0, color: 'purple', }; return { boxShadow: [withTiming(active.value ? boxShadow2 : boxShadow1)] }; }); ``` But this fix ensures we can also animated particular fields: ```tsx const shadowStyles = useAnimatedStyle(() => { return { boxShadow: [ { offsetX: 10, offsetY: 15, blurRadius: withTiming(active.value ? 36 : 23), }, ], }; ``` ## Test plan You can ran this example on iOS and Android and make sure both squares change shadow after click. I've tested on both iOS and Android and it worked. <details> <summary>Example code</summary> ```tsx import { useEffect } from 'react'; import { TouchableWithoutFeedback, StyleSheet, Pressable, View, Text, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import Animated, { useAnimatedStyle, useSharedValue, withTiming, withDelay, withSpring, interpolateColor, } from 'react-native-reanimated'; const SIZE = 100; export default function EmptyExample() { const active = useSharedValue(false); const handlePress = () => { active.value = !active.value; }; const shadowStylesWholeObject = useAnimatedStyle(() => { const boxShadow1 = { offsetX: 10, offsetY: 15, blurRadius: 23 }; const boxShadow2 = { offsetX: 10, offsetY: 15, blurRadius: 36 }; return { boxShadow: [withTiming(active.value ? boxShadow2 : boxShadow1)] }; }); const shadowStyles = useAnimatedStyle(() => { return { boxShadow: [ { offsetX: 10, offsetY: 15, blurRadius: withTiming(active.value ? 36 : 23), }, ], }; }); return ( <SafeAreaView style={{ alignItems: 'center', flex: 1 }}> <Text style={styles.title}>boxShadow animated as a whole object</Text> <Animated.View style={[ { backgroundColor: '#b07eff' }, styles.box, shadowStylesWholeObject, ]} /> <Text style={styles.title}>boxShadow animated as a whole object</Text> <Animated.View style={[{ backgroundColor: 'hotpink' }, styles.box, shadowStyles]} /> <Pressable style={styles.button} onPress={handlePress}> <Text style={{ fontFamily: 'Poppins', color: '#d1bbf3' }}> Toggle Animation </Text> </Pressable> </SafeAreaView> ); } const styles = StyleSheet.create({ title: { fontFamily: 'Poppins', fontSize: 16, fontWeight: 'bold', textAlign: 'center', marginBottom: 20, }, box: { height: SIZE, width: SIZE, marginBottom: 25, borderRadius: 10 }, button: { marginTop: 36, backgroundColor: '#001a72', borderRadius: 16, padding: 12, }, }); ``` </details>
1 parent 9e76d1d commit df17439

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

packages/react-native-reanimated/src/hook/useAnimatedStyle.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ function runAnimations(
162162
/*
163163
* If `animation.current` is a boxShadow object, spread its properties into a new object
164164
* to avoid modifying the original reference. This ensures when `newValues` has a nested color prop, it stays unparsed
165-
* in rgba format, allowing the animation to run correctly.
165+
* in rgba format, allowing the animation to run correctly. Additionally we need to check if user animated the whole boxShadow object or only one of its properties.
166166
*/
167-
if (forceCopyAnimation) {
167+
if (forceCopyAnimation && typeof animation.current === 'object') {
168168
result[key] = { ...animation.current };
169169
} else {
170170
result[key] = animation.current;

0 commit comments

Comments
 (0)