Reputation: 173
I’m trying to increase the size of an image on user press and decrease it when he presses again with animated API using the following:
const [viewState, setViewState]= useState(true);
const scaleAnim = (new Animated.Value(.9))
const scaleOut = () => {
if(viewState){
Animated.timing(scaleAnim, {
toValue: 2.2,
duration: 2000,
useNativeDriver:true,
}).start(()=>{setViewState(false)});
}
else{
Animated.timing(scaleAnim, {
toValue: .9,
duration: 700,
useNativeDriver:true,
}).start(setViewState(true));
}
};
<Animated.View style={{transform:[{scale:scaleAnim}]}} >
<Image style={styles.image} source={require('../path..')} />
</Animated.View>
const styles = StyleSheet.create({
image: {
width:70,
resizeMode:"contain",
height: 45,
alignSelf: "center",
},
But the issue is, whenever the duration is over, the size is going back to default. I want to to stay permanently and do the opposite when the user presses again(decrease size)
Any suggestions?
Upvotes: 0
Views: 1400
Reputation: 3540
Firstly you want your animated value to either useState
or useRef
. The react-native example uses useRef, so I'd suggest you to do the same. I'd also suggest tha you use an interpolation to scale so that you can tie more animations to that one animated value. The result would be something like this:
const animatedValue = useRef(new Animated.Value(0)).current;
const [ toggle, setToggle ] = useState(false)
const scaleOut = () => {
let animation
if(!toggle){
animation = Animated.timing(animatedValue, {
toValue: 1,
duration: 700,
useNativeDriver:true,
});
}
else{
animation = Animated.timing(animatedValue, {
toValue: 0,
duration: 2000,
useNativeDriver:true,
});
}
animation.start(()=>{
setToggle(!toggle)
})
};
let scaleAnim = animatedValue.interpolate({
inputRange:[0,1],
outputRange:[0.9,2.2]
})
return (
<Animated.View style={{transform:[{scale:scaleAnim}]}} >
<TouchableOpacity onPress={scaleOut}>
<Image style={styles.image} source={require('../path..')} />
</TouchableOpacity>
</Animated.View>
);
By doing this, you can scale multiple images at whatever size you want by just adding another interpolation. But if you have no desire to do that:
const scaleOut = () => {
let animation
if(!toggle){
animation = Animated.timing(animatedValue, {
toValue: 2.2,
duration: 2000,
useNativeDriver:true,
});
}
else{
animation = Animated.timing(animatedValue, {
toValue: 0.9,
duration: 700,
useNativeDriver:true,
});
}
animation.start(()=>{
setToggle(!toggle)
})
};
return (
<Animated.View style={{transform:[{scale:animatedValue}]}} >
<TouchableOpacity onPress={scaleOut} />
<Image style={styles.image} source={require('../path..')} />
</TouchableOpacity>
</Animated.View>
);
If you want to go a step further, swap out the TouchableOpacity for a Pressable, put the animations in a Animated.loop
and start that in onPressIn, and on pressOut stop the animations and bring the set the animatedValue back to initial value:
const onPressIn= ()=>{
Animated.loop([
Animated.timing(animatedValue, {
toValue: 2.2,
duration: 2000,
useNativeDriver:true,
}),
Animated.timing(animatedValue, {
toValue: 0.9,
duration: 700,
useNativeDriver:true,
});
],{useNativeDriver:true}).start()
}
const onPressOut= ()=>{
animatedValue.stop()
Animated.timing(animatedValue,{
toValue: 0.9,
duration: 700,
useNativeDriver:true,
})
}
return(
<Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
<Animated.View style={{transform:[{scale:animatedValue}]}} >
<Image style={styles.image} source={require('../path..')} />
</Animated.View>
</Pressable>
);
Upvotes: 0
Reputation: 1728
Created a Component hope this is how you wanted....
snack: https://snack.expo.io/neEtc2ihJ
export default function App() {
const [viewState, setViewState] = React.useState(true);
const scale = React.useRef(new Animated.Value(1)).current;
const [init, setInit] = React.useState(true);
React.useEffect(() => {
if (init) {
setInit(false);
} else {
if (viewState) {
Animated.timing(scale, {
toValue: 2,
duration: 1000,
useNativeDriver: true,
}).start();
} else {
Animated.timing(scale, {
toValue: 0.5,
duration: 700,
useNativeDriver: true,
}).start();
}
}
}, [viewState]);
const scaleOut = () => {
setViewState(!viewState);
};
return (
<View style={styles.container}>
<Animated.View style={{ transform: [{ scale }] }}>
<Image
style={styles.image}
source={require('./assets/snack-icon.png')}
/>
</Animated.View>
<Button title="animate" onPress={scaleOut} />
</View>
);
}
Upvotes: 1