I am very new to React Native and have come across a problem which occurs when I want to animate an images tint color. I expect the color to change gradually over time like Animated.Timing should achieve, but instead it only does the first frame of the animation then freezes. However, for some reason when I just change 'tintColor' to 'backgroundColor' the animation works fine.
Here is my code:
import React from 'react';
import { useState } from 'react';
import { Text, View, TouchableHighlight, Dimensions, Component, Image, Animated } from 'react-native';
import PropTypes from 'prop-types';
function RGBtoCSS(rgb) {
return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
}
class MyImage extends React.Component {
constructor(props) {
super(props);
this.anim = new Animated.Value(0);
this.animate();
}
animate() {
this.props.onPress();
Animated.timing(
this.anim,
{
toValue: 1,
duration: 500,
useNativeDriver: false
}
).start();
}
render() {
var style = {
width: 500,
height: 500,
resizeMode: 'stretch'
};
var col = this.anim.interpolate(
{
inputRange: [0, 1],
outputRange: [RGBtoCSS([0, 0, 0]), RGBtoCSS([140, 74, 140])]
});
return (
<Animated.Image source={this.props.img} style={{ ...style, tintColor: col }} />
);
}
}
MyImage.propTypes = { img: PropTypes.string.isRequired, onPress: PropTypes.func.isRequired, spacing: PropTypes.number.isRequired };
export default function App() {
return (
<View style={{
flex: 1,
backgroundColor: RGBtoCSS([255, 255, 255])
}}>
<MyImage img={{ uri: 'https://img.icons8.com/color/452/google-logo.png' }} onPress={() => { }} spacing={0} />
</View>
);
}
(demo available at https://snack.expo.dev/v0GeiLbOP)
I found a workaround for this. You can stack two <Animated.Image> on top of each other, with 1st Image being of final color, and 2nd image being of starting color. Then you can use opacity to create a fading effect, between these two Images, which also works well with interpolate.
import React from 'react';
import { useState } from 'react';
import { Text, View, TouchableHighlight, Dimensions, Component, Image, Animated } from 'react-native';
import PropTypes from 'prop-types';
function RGBtoCSS(rgb) {
return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] +")";
}
class MyImage extends React.Component {
constructor(props) {
super(props);
this.anim = new Animated.Value(0);
this.animate();
}
animate() {
this.props.onPress();
console.log(this.anim)
Animated.timing(
this.anim,
{
toValue: 1,
duration: 500,
useNativeDriver: false
}
).start();
}
render() {
var style = {
width: 500,
height: 500,
resizeMode: 'stretch'
};
var col = this.anim.interpolate(
{
inputRange: [0, 1],
outputRange: [1, 0]
});
return (
<View>
<Animated.Image source={this.props.img} style={{ ...style,tintColor: RGBtoCSS([140, 74, 140]) }} />
<Animated.Image source={this.props.img} style={{ ...style, opacity:col, transform:[{translateY:"-100%"}], tintColor: RGBtoCSS([0, 0, 0]) }} />
</View>
);
}
}
MyImage.propTypes = { img: PropTypes.string.isRequired, onPress: PropTypes.func.isRequired, spacing: PropTypes.number.isRequired };
export default function App() {
return (
<View style={{
flex: 1,
backgroundColor: RGBtoCSS([255, 255, 255])
}}>
<MyImage img={{ uri: 'https://img.icons8.com/color/452/google-logo.png' }} onPress={() => { }} spacing={0} />
</View>
);
}
Snack - https://snack.expo.dev/ZYulbKh3g