问题
I have two images with little difference between them and each corresponding to a particular state. I need to smoothly transition from one to the other when I change the state so that the effect feels like only the part which is different in the two images has undergone animation,the rest of the image staying as it is.
I want it to work so that when I render the second image on stateChange, only the rod like part in the second image appears to fade in,the rest remaining still.
I think this can be achieved without using any animation libraries like react-transition-group
probably by using some of the life cycle methods in React and obviously, the AnimatedAPI. The major issue that I am facing is that when I update the state I have no control over the previous image that was rendered. I somehow want the previously rendered image to stay until newly rendered Component appears and does its animation. Here is what I tried to do. I have this ImageLoader Component which renders an image while providing a fading-in animation to it.
class ImageLoader extends React.Component {
constructor(){
super()
this.opacity= new Animated.Value(0)
}
componentDidUpdate(){
{this.onLoad()}
}
onLoad = () => {
this.opacity.setValue(0);
Animated.timing(this.opacity, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}).start();
}
render() {
return (
<Animated.Image onLoad={this.onLoad}{...this.props}style={[
{opacity: this.opacity,}, this.props.style,
]}
/>
);
}
}
export default class App extends React.Component {
state={
no:1,
}
render() {
let Dun=()=>{return this.state.no==1?
<ImageLoader source={require('./assets/img1.PNG')}/>: <ImageLoader
source={require('./assets/img2.PNG')}/>
}
const calc=()=>{
this.setState((state)=>({no:Math.abs(state.no-1)}));
}
return (
<View style={styles.container}>
<View style={{height:100,marginLeft:50}}>
{Dun()}
<Button onPress={()=>{calc()}}> Press</Button>
</View>
</View>
);
}
}
回答1:
You could use 2 animated images to give the impression that one is fading into the other. Here is a solution based on your example:
import React from 'react';
import { Animated, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import images from 'src/images';
const styles = StyleSheet.create({
image: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0
}
});
class ImageSwitcher extends React.Component {
fadeInOpacity = new Animated.Value(0);
fadeOutOpacity = new Animated.Value(1);
state = {
prevSource: null
};
componentDidMount() {
this.onLoad();
}
componentDidUpdate() {
this.onLoad();
}
componentWillReceiveProps({ source: newSource }) {
const { source } = this.props;
if (newSource !== source) {
this.setState({ prevSource: source });
}
}
onLoad = () => {
this.fadeInOpacity.setValue(0);
this.fadeOutOpacity.setValue(1);
Animated.timing(this.fadeInOpacity, {
toValue: 1,
duration: 500,
useNativeDriver: true
}).start();
Animated.timing(this.fadeOutOpacity, {
toValue: 0,
duration: 500,
useNativeDriver: true
}).start();
};
render() {
const { prevSource } = this.state;
return (
<View
style={{
width: 200,
height: 200
}}
>
<Animated.Image {...this.props} style={[styles.image, { opacity: this.fadeInOpacity }]} resizeMode="cover" />
{prevSource && (
<Animated.Image {...this.props} style={[styles.image, { opacity: this.fadeOutOpacity }]} resizeMode="cover" source={prevSource} />
)}
</View>
);
}
}
export default class App extends React.Component {
state = {
source: images.first
};
handleToggle = () => this.setState(({ source }) => ({ source: source === images.first ? images.second : images.first }));
render() {
const { source } = this.state;
return (
<View style={{ flex: 1 }}>
<ImageSwitcher source={source} />
<TouchableOpacity onPress={this.handleToggle}>
<Text>Toggle Image</Text>
</TouchableOpacity>
</View>
);
}
}
来源:https://stackoverflow.com/questions/56882353/how-do-i-transition-from-one-image-to-another-by-changing-state-in-react-native