Skip to content

Commit

Permalink
fix: withSpring color properties flickering (#6821)
Browse files Browse the repository at this point in the history
## Summary

This PR addresses an issue where color-based properties
(`backgroundColor`, `boxShadow`) were causing flickering when used with
withSpring animations. The root cause of the flickering was RGBA values
going below `0`, resulting in `NaN` values.

I introduced `clampRGBA` function that guards values within given
limits.

Before:


https://github.com/user-attachments/assets/ace128a8-3f4b-41be-98c6-d34339808283

After:


https://github.com/user-attachments/assets/b29f1248-2385-48c2-8fad-e261ee21b46a




## Test plan

Paste this code to EmptyExample - it should work on both Paper and
Fabric:

<details>
<summary>EmptyExample code</summary>

```js
import { Text, StyleSheet, View, Pressable } from 'react-native';
import React from 'react';
import Animated, {
  useSharedValue,
  withSpring,
  useAnimatedStyle,
} from 'react-native-reanimated';

export default function EmptyExample() {
  const pressed = useSharedValue(false);
  const animatedStyle = useAnimatedStyle(() => {
    return {
      backgroundColor: withSpring(pressed.value ? 'blue' : 'red'),
    };
  });

  return (
    <View>
      <Animated.View style={[styles.box, animatedStyle]} />
      <Pressable
        onPress={() => {
          pressed.value = !pressed.value;
        }}>
        <Text>Press me</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  box: {
    width: 50,
    height: 50,
  },
});

```

</details>
  • Loading branch information
patrycjakalinska authored Jan 29, 2025
1 parent 0e0cf96 commit ff2ca92
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/react-native-reanimated/src/Colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ function parsePercentage(str: string): number {
return int / 100;
}

export function clampRGBA(RGBA: ParsedColorArray): void {
'worklet';
for (let i = 0; i < 4; i++) {
RGBA[i] = Math.max(0, Math.min(RGBA[i], 1));
}
}

const names: Record<string, number> = makeShareable({
transparent: 0x00000000,

Expand Down
7 changes: 7 additions & 0 deletions packages/react-native-reanimated/src/animation/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
rgbaArrayToRGBAColor,
toGammaSpace,
toLinearSpace,
clampRGBA,
} from '../Colors';
import { ReduceMotion, isWorkletFunction } from '../commonTypes';
import type {
Expand Down Expand Up @@ -263,6 +264,9 @@ function decorateAnimation<T extends AnimationObject | StyleLayoutAnimation>(
res.push(animation[i].current);
});

// We need to clamp the res values to make sure they are in the correct RGBA range
clampRGBA(res as ParsedColorArray);

animation.current = rgbaArrayToRGBAColor(
toGammaSpace(res as ParsedColorArray)
);
Expand All @@ -283,6 +287,9 @@ function decorateAnimation<T extends AnimationObject | StyleLayoutAnimation>(
res.push(animation[i].current);
});

// We need to clamp the res values to make sure they are in the correct RGBA range
clampRGBA(res as ParsedColorArray);

animation.current = rgbaArrayToRGBAColor(
toGammaSpace(res as ParsedColorArray)
);
Expand Down

0 comments on commit ff2ca92

Please sign in to comment.