Skip to content

Add support for remaining synchronous props on Android #7962

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

Merged
merged 5 commits into from
Aug 1, 2025

Conversation

tomekzaw
Copy link
Member

@tomekzaw tomekzaw commented Jul 31, 2025

Summary

This PR adds support for the animating remaining synchronous props using a fast path on Android (which is still hidden behind ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS static Reanimated feature flag).

After this change, all props from NativeAnimatedAllowlist.js are supported, except for scaleX, scaleY, translateX, translateY (which are deprecated outside of transform), shadowOffset, shadowOpacity (which are not supported on Android at all) and color (which doesn't work for some unknown reason).

Even though elevation and zIndex are supposed to be integers, I decided to pass them as double to achieve the same behavior as when animating them via ShadowTree.

TODO

  • Add support other react-native props, e.g. filter, outlineColor, placeholderTextColor etc.
  • Add support for other react-native-svg props, e.g. fill, stroke etc.

Test plan

Enable ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS static feature flag

tintColor

import React, { useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';

export default function EmptyExample() {
  const sv = useSharedValue(0);

  useEffect(() => {
    sv.value = 0;
    sv.value = withRepeat(withTiming(1, { duration: 500 }), -1, true);
  }, [sv]);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      tintColor: interpolateColor(sv.value, [0, 1], ['red', 'blue']),
    };
  });

  return (
    <View style={styles.container}>
      <Animated.Image
        style={[{ width: 50, height: 50 }, animatedStyle]}
        source={{
          uri: 'https://raw.githubusercontent.com/facebook/react-native/refs/heads/main/packages/rn-tester/js/assets/uie_thumb_normal%402x.png',
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

@tomekzaw tomekzaw added this pull request to the merge queue Aug 1, 2025
Merged via the queue into main with commit d08c46d Aug 1, 2025
17 checks passed
@tomekzaw tomekzaw deleted the @tomekzaw/support-all-synchronous-props branch August 1, 2025 09:00
@MatiPl01 MatiPl01 mentioned this pull request Aug 4, 2025
15 tasks
MatiPl01 pushed a commit that referenced this pull request Aug 4, 2025
## Summary

This PR adds support for the animating remaining synchronous props using
a fast path on Android (which is still hidden behind
`ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static Reanimated feature flag).

After this change, all props from
[NativeAnimatedAllowlist.js](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Animated/NativeAnimatedAllowlist.js)
are supported, except for `scaleX`, `scaleY`, `translateX`, `translateY`
(which are deprecated outside of `transform`), `shadowOffset`,
`shadowOpacity` (which are not supported on Android at all) and `color`
(which doesn't work for some unknown reason).

Even though `elevation` and `zIndex` are supposed to be integers, I
decided to pass them as double to achieve the same behavior as when
animating them via `ShadowTree`.

## TODO

* Add support other `react-native` props, e.g. `filter`, `outlineColor`,
`placeholderTextColor` etc.
* Add support for other `react-native-svg` props, e.g. `fill`, `stroke`
etc.

## Test plan

Enable `ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static feature flag

<details>
<summary>

`tintColor`
</summary>

```tsx
import React, { useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';

export default function EmptyExample() {
  const sv = useSharedValue(0);

  useEffect(() => {
    sv.value = 0;
    sv.value = withRepeat(withTiming(1, { duration: 500 }), -1, true);
  }, [sv]);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      tintColor: interpolateColor(sv.value, [0, 1], ['red', 'blue']),
    };
  });

  return (
    <View style={styles.container}>
      <Animated.Image
        style={[{ width: 50, height: 50 }, animatedStyle]}
        source={{
          uri: 'https://raw.githubusercontent.com/facebook/react-native/refs/heads/main/packages/rn-tester/js/assets/uie_thumb_normal%402x.png',
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

</details>
MatiPl01 pushed a commit that referenced this pull request Aug 4, 2025
## Summary

This PR adds support for the animating remaining synchronous props using
a fast path on Android (which is still hidden behind
`ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static Reanimated feature flag).

After this change, all props from
[NativeAnimatedAllowlist.js](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Animated/NativeAnimatedAllowlist.js)
are supported, except for `scaleX`, `scaleY`, `translateX`, `translateY`
(which are deprecated outside of `transform`), `shadowOffset`,
`shadowOpacity` (which are not supported on Android at all) and `color`
(which doesn't work for some unknown reason).

Even though `elevation` and `zIndex` are supposed to be integers, I
decided to pass them as double to achieve the same behavior as when
animating them via `ShadowTree`.

## TODO

* Add support other `react-native` props, e.g. `filter`, `outlineColor`,
`placeholderTextColor` etc.
* Add support for other `react-native-svg` props, e.g. `fill`, `stroke`
etc.

## Test plan

Enable `ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static feature flag

<details>
<summary>

`tintColor`
</summary>

```tsx
import React, { useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';

export default function EmptyExample() {
  const sv = useSharedValue(0);

  useEffect(() => {
    sv.value = 0;
    sv.value = withRepeat(withTiming(1, { duration: 500 }), -1, true);
  }, [sv]);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      tintColor: interpolateColor(sv.value, [0, 1], ['red', 'blue']),
    };
  });

  return (
    <View style={styles.container}>
      <Animated.Image
        style={[{ width: 50, height: 50 }, animatedStyle]}
        source={{
          uri: 'https://raw.githubusercontent.com/facebook/react-native/refs/heads/main/packages/rn-tester/js/assets/uie_thumb_normal%402x.png',
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

</details>
MatiPl01 pushed a commit that referenced this pull request Aug 5, 2025
## Summary

This PR adds support for the animating remaining synchronous props using
a fast path on Android (which is still hidden behind
`ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static Reanimated feature flag).

After this change, all props from
[NativeAnimatedAllowlist.js](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Animated/NativeAnimatedAllowlist.js)
are supported, except for `scaleX`, `scaleY`, `translateX`, `translateY`
(which are deprecated outside of `transform`), `shadowOffset`,
`shadowOpacity` (which are not supported on Android at all) and `color`
(which doesn't work for some unknown reason).

Even though `elevation` and `zIndex` are supposed to be integers, I
decided to pass them as double to achieve the same behavior as when
animating them via `ShadowTree`.

## TODO

* Add support other `react-native` props, e.g. `filter`, `outlineColor`,
`placeholderTextColor` etc.
* Add support for other `react-native-svg` props, e.g. `fill`, `stroke`
etc.

## Test plan

Enable `ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` static feature flag

<details>
<summary>

`tintColor`
</summary>

```tsx
import React, { useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';

export default function EmptyExample() {
  const sv = useSharedValue(0);

  useEffect(() => {
    sv.value = 0;
    sv.value = withRepeat(withTiming(1, { duration: 500 }), -1, true);
  }, [sv]);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      tintColor: interpolateColor(sv.value, [0, 1], ['red', 'blue']),
    };
  });

  return (
    <View style={styles.container}>
      <Animated.Image
        style={[{ width: 50, height: 50 }, animatedStyle]}
        source={{
          uri: 'https://raw.githubusercontent.com/facebook/react-native/refs/heads/main/packages/rn-tester/js/assets/uie_thumb_normal%402x.png',
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

</details>
MatiPl01 added a commit that referenced this pull request Aug 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants