React-Native Fade Out animation with Hooks - javascript

This is a React Native app. I'm implementing "cover" component that displays an image, once video is loaded, image fades out and video is playing instead. Here is my code:
export default function Cover() {
const [playVideo, setPlayVideo] = useState(false);
const [coverOpacityAnimation] = useState(new Animated.Value(1))
useEffect(() => {
if (!playVideo) return;
Animated.timing(coverOpacityAnimation, {
toValue: 0,
duration: 1000
}).start()
}, [playVideo])
return (
<View>
<Animated.View style={{opacity: coverOpacityAnimation}}>
<Image source={{uri: data.cover}} />
</Animated.View>
<Video
source={{uri: 'https://videostorage.net/public/video.mp4'}}
onReadyForDisplay={() => setPlayVideo(true)} />
</View>
);
}
The issue that I'm having is, when setPayVideo(true) is called from Video component fading out is not happening, image just disappears and video is playing. If I do:
useEffect(() => {
Animated.timing(coverOpacityAnimation, {
toValue: 0,
duration: 1000
}).start()
})
Animation works as expected. I need to trigger it from Video onReadyForDisplay. New to hooks - please help :)

Related

I'm trying to display the Image after the lotti progress finished and disappeared but I couldn't in react native

Here is my code:
const Success =({navigation})=>{
useEffect(() => {
setTimeout(()=>{
<View>
<Image source={images.done}
style={{
width:100,
height:100
}}
/>
</View>
navigation.navigate('Home')
},4000)
}, [])
return(
<View style={{
flex:1,
justifyContent:'center',
alignItems:'center',
}}>
<LottieView
style={{
width: 100,
height: 60,
}}
source={images.progress}
autoPlay
/>
</View>
)
}
export default Success ;
Please Help me out How I can display first Lotti progress and then immediately I wanna the image done appears after the Lotti progress finish and disappear. so I would know how to set time for Lotti progress and then set time to display the Image done then navigate to the next page
You can make use of onAnimationFinish props in lottie-react-native library. Tell the program what you are going to do when the lottie animation end.
const Success = ({navigation}) => {
const [lottieFinished, setLottieFinished] = useState(false);
const onAnimationFinish = () => {
setLottieFinished(true);
setTimeout(() => {
//Go Back to home page after 4 seconds
navigation.navigate('Home')
}, 4000);
}
return (
<View>
{
!lottieFinished ?
<LottieView
source={images.progress}
autoPlay
loop={false}
onAnimationFinish={onAnimationFinish}
/>
:
<Image
source={images.done}
style={{height:100, width:100}}
/>
}
</View>
);
}

React native: error with animated value on progress bar

In my react native app I want to have a progressbar animated values, problem is when component is mounted the bar is full already (View with backgroundColor RED is visible) even though progressValue is 0 according to my console logs... if I execute onStart nothing moves since it appears like animation already finished...
Is it because I'm using translate wrongly? How can I achieve correct animated effect?
const width = Math.round(Dimensions.get('window').width)-30;
const progressValue = new Animated.Value(0);
//const animation = null;
const onStart = (duration ) =>
{
console.log(duration,width);
const animation = Animated.timing(progressValue, {
duration: duration,
toValue: width,
easing: Easing.linear,
useNativeDriver: true,
}).start();
};
<View style={{width: width, height: 4,backgroundColor: 'white'}}>
<Animated.View style={{width: width, height: 4, backgroundColor: 'red', transform: [{translateX: progressValue}]}} />
</View>
two things which i can see, always useRef for animation values
const width = Math.round(Dimensions.get('window').width)-30;
const progressValue = useRef(new Animated.Value(0)).current; // add this
//const animation = null;
const onStart = useCallback((duration ) =>
{
console.log(duration,width);
const animation = Animated.timing(progressValue, {
duration: duration,
toValue: width,
easing: Easing.linear,
useNativeDriver: true,
}).start();
},[progressValue]);
<View style={{width: width, height: 4,backgroundColor: 'white'}}>
<Animated.View style={{width: width, height: 4, backgroundColor: 'red', transform: [{translateX: progressValue}]}} />
</View>
Also im hoping youre calling onStart in a useEffect like this
useEffect(() => {
onStart()
},[onStart])
Hope it helps. feel free for doubts

Why are other images from media library displaying in react native / expo project?

My fairly basic react native project uses expo-media-library to retrieve some photographs from a users photo album, presenting them in a stack of cards - kinda similar to Tinder. My code generally works, however instead of just displaying the top photo/card, several others are displayed in the first few seconds and I can't figure out why. I think it has to do with the size of the images and the delay in loading them but I'm not sure. I'd really appreciate advice about how to fix this.
Here's what's happening:
As you can see, instead of displaying the first image on the stack, another image is displayed briefly first even though I have not coded for this to happen.
Here is my code (leaving out imports and styles):
const ImageStack = ({navigation, route}) => {
const [status, requestPermission] = MediaLibrary.usePermissions()
const [photos, setPhotos] = useState([]) //where we store stack of cards
const [isLoading, setIsLoading]=useState(true) //only displaying stack when images have loaded
// On load, retrieve photos from gallery
useEffect(async()=>{
const getPhotos = await getAllPhotos(route.params.id)//id for the album is passed to component
setPhotos(getPhotos)
setIsLoading(false) // only when photos have been retrieved should they be displayed
},[])
// function to retrieve photos from gallery
const getAllPhotos = async (id) => {
let album = await MediaLibrary.getAssetsAsync({album: id, mediaType: 'photo', first: 20, sortBy: ['creationTime']})
const foundPhotos = album['assets']
const updatedPhotos = []
for (let i=0;i<foundPhotos.length;i++){
const updatedPhoto = await MediaLibrary.getAssetInfoAsync(foundPhotos[i].id)
updatedPhotos.push({
uri: updatedPhoto['localUri'],
id: updatedPhoto['id']
})
}
return updatedPhotos
}
const renderCards = () => {
return photos.map((item, i)=>{
return(
<Animated.View key={item.id} style={{height: SCREEN_HEIGHT -120, width: SCREEN_WIDTH, padding: 10, position: 'absolute'}}>
<Image source={{uri: item.uri}} style={{flex: 1, height: null, width: null, resizeMode: 'cover', borderRadius: 20}}/>
</Animated.View>
)
})
}
return (
<View style={{flex:1}}>
<View style={{height:60}}>
</View>
<View style={{flex:1}}>
{!isLoading && renderCards()} //Only render the photo cards when loaded
</View>
<View style={{height:60}}>
</View>
</View>
Any suggestion how to fix this? Thanks!
Fixed this. So the issue was the size of the images. I added image compression which completely fixed the problem:
const compressedImage = await ImageManipulator.manipulateAsync(updatedPhoto.localUri, [], { compress: 0.2 });

React native Animated stop is not working

I am trying to use React Native Animated to do simple animation with View width and Height.
Following the official syntax from here React Animated. But the stop functionality is not working.
Here is my code snippet:
import React, { useRef } from "react";
import { Animated, View, StyleSheet, Button } from "react-native";
const App = () => {
const sizeAnimBase = new Animated.Value(100);
const sizeAnim = useRef(sizeAnimBase).current;
const startAnimation = () => {
Animated.timing(sizeAnim, {
toValue: 500,
duration: 100,
useNativeDriver: false
}).start(() => {
});
}
const stopAnimation = () => {
// Tried both ways but didn't work
Animated.timing(sizeAnimBase).stop();
Animated.timing(sizeAnim).stop();
}
return (
<View>
<Animated.View
style={
width: sizeAnim,
height: sizeAnim
}
>
<Text>Animated view</Text>
</Animated.View>
<Button title="Start Animation" onPress={startAnimation} />
<Button title="Stop Animation" onPress={stopAnimation} />
</View>
)
}
This worked for me normally
const App = () => {
const sizeAnim = useRef(new Animated.Value(100)).current;
const startAnimation = () => {
Animated.timing(sizeAnim, {
toValue: 500,
duration: 2000,
useNativeDriver: false,
}).start();
};
const stopAnimation = () => {
Animated.timing(sizeAnim, {
duration: 0,
toValue: 0,
useNativeDriver: true,
}).stop();
};
return (
<View>
<Animated.View style={{width: sizeAnim, height: sizeAnim}}>
<Text>Animated view</Text>
</Animated.View>
<Button title="Start Animation" onPress={startAnimation} />
<Button title="Stop Animation" onPress={stopAnimation} />
</View>
);
}
How are you testing whether it's working or not? You've set duration to 100ms, its practically impossible to press Stop Animation button before the animation completes.
Increase the duration to something like 5000ms and you'll set it's working perfectly.
Here is a snack link.

Can't call function on react-native-video item

I'm attempting to display an image and call a Video component onPress. The image displays fine, but I cannot get the video to play the same way I can get an alert to show.
Two images are displayed, if one is clicked then an alert shows. This works fine. If the other image is clicked, then the video should play.
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
TouchableHighlight,
Image,
Text,
Component,
AlertIOS,
View,
} = React;
var Video = require('react-native-video');
class Mogul extends Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this.playBroadchurch}>
<Image
style={{ height:150, width: 150 }}
source={{uri: 'http://www.covermesongs.com/wp-content/uploads/2014/05/NotoriousBIG.jpg'}}
/>
</TouchableHighlight>
<TouchableHighlight onPress={this.showAlert}>
<Image
style={{ height:150, width: 150 }}
source={{uri: 'http://www.covermesongs.com/wp-content/uploads/2014/05/NotoriousBIG.jpg'}}
/>
</TouchableHighlight>
</View>
);
}
playBroadchurch() {
return (
<Video source={{uri: "broadchurch"}} // Can be a URL or a local file.
rate={1} // 0 is paused, 1 is normal.
volume={1} // 0 is muted, 1 is normal.
muted={false} // Mutes the audio entirely.
// Pauses playback entirely.
resizeMode={'contain'} // Fill the whole screen at aspect ratio.
repeat={false} // Repeat forever.
onLoad={this.setDuration} // Callback when video loads
onProgress={this.setTime} // Callback every ~250ms with currentTime
onEnd={this.onEnd} // Callback when playback finishes
style={styles.video} />
);
}
showAlert() {
AlertIOS.alert('Notorious BIG', 'It was all a DREAM',
[
{text: 'Yep', onPress: () => console.log('Yep Pressed!')},
{text: 'Nope', onPress: () => console.log('Nope Pressed!')},
]
)
}
};
When you return a component from an event handler, React Native doesn't do anything with it. Instead, you should set state on the component, and use that to decide whether to display the video or not. Something like this:
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
TouchableHighlight,
Image,
Text,
Component,
AlertIOS,
View,
} = React;
var Video = require('react-native-video');
class Mogul extends Component {
constructor() {
this.playBroadchurch = this.playBroadchurch.bind(this)
this.state = {showBroadchurch: false};
}
render() {
var videoDisplay;
if (this.state.showBroadchurch) { // Switch between showing video and placeholder image
videoDisplay = <Video source={{uri: "broadchurch"}} // Can be a URL or a local file.
rate={1} // 0 is paused, 1 is normal.
volume={1} // 0 is muted, 1 is normal.
muted={false} // Mutes the audio entirely.
// Pauses playback entirely.
resizeMode={'contain'} // Fill the whole screen at aspect ratio.
repeat={false} // Repeat forever.
onLoad={this.setDuration} // Callback when video loads
onProgress={this.setTime} // Callback every ~250ms with currentTime
onEnd={this.onEnd} // Callback when playback finishes
style={styles.video} />;
} else {
videoDisplay = <Image
style={{ height:150, width: 150 }}
source={{uri: 'http://www.covermesongs.com/wp-content/uploads/2014/05/NotoriousBIG.jpg'}}
/>;
}
return (
<View style={styles.container}>
<TouchableHighlight onPress={this.playBroadchurch}>
{videoDisplay}
</TouchableHighlight>
<TouchableHighlight onPress={this.showAlert}>
<Image
style={{ height:150, width: 150 }}
source={{uri: 'http://www.covermesongs.com/wp-content/uploads/2014/05/NotoriousBIG.jpg'}}
/>
</TouchableHighlight>
</View>
);
}
playBroadchurch() {
this.setState({showBroadchurch: true}); // Update state to show video
}
showAlert() {
AlertIOS.alert('Notorious BIG', 'It was all a DREAM',
[
{text: 'Yep', onPress: () => console.log('Yep Pressed!')},
{text: 'Nope', onPress: () => console.log('Nope Pressed!')},
]
)
}
};

Categories