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

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!')},
]
)
}
};

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>
);
}

Loadingspinner while Images is loading from URL

In my React Native applikation I render a <FlatList> with Images. I pass the direct imageurl as source into the <Image> Component.
<FlatList
data={this.state.images}
keyExtractor={item => item.imageToken}
renderItem={({ item }) => (
<Image key={item.imageToken} style={{ marginRight: 2, marginTop: 2, width: '50%', opacity: 1 }} source={{ uri: item.imageUrl }} alt="Alternate Text" size="xl" /> )} />
This means that the images are loaded in a different order because they are also different sizes. I would like to show a placeholder during loading.
The listAll() function resets isLoading to false before all images are displayed. Is there a 'trigger' when an image is fully visible in the view? I can't just build a single state for each image - I guess.
There will be many hundreds of pictures!
I think it's important to know that I extract the url from the google firestore images and store they as an array in state beforehand. See function getDownloadURL
Fullcode
import React, { Component } from 'react'
import { StyleSheet, SafeAreaView, ActivityIndicator } from 'react-native'
import { Image, FlatList, Center, Box } from "native-base"
import EventGalleryHeader from '../components/EventGalleryHeader.js'
import { getStorage, ref, getDownloadURL, list, listAll } from "firebase/storage"
import { LongPressGestureHandler, State } from 'react-native-gesture-handler'
export default class EventScreen extends Component {
constructor(props) {
super(props);
this.storage = getStorage()
this.pathToImages = '/eventimages/'
this.eventImageSource = this.props.route.params.eventData.key
this.imagesRef = this.pathToImages + this.eventImageSource
this.state = {
isLoading: true,
images: [],
event: {
adress: this.props.route.params.eventData.adress,
hosts: this.props.route.params.eventData.hosts,
description: this.props.route.params.eventData.description,
eventtitle: this.props.route.params.eventData.eventtitle,
invitecode: this.props.route.params.eventData.invitecode,
key: this.props.route.params.eventData.key,
timestamp: this.props.route.params.eventData.timestamp,
}
}
}
componentDidMount() {
this.getEventImageData()
}
componentWillUnmount() {
}
getEventImageData() {
const images = []
const event = {
adress: this.props.route.params.eventData.adress,
description: this.props.route.params.eventData.description,
eventtitle: this.props.route.params.eventData.eventtitle,
key: this.props.route.params.eventData.key,
timestamp: this.props.route.params.eventData.timestamp,
}
listAll(ref(this.storage, this.imagesRef))
.then((res) => {
res.items.forEach((itemRef) => {
getDownloadURL(itemRef)
.then((url) => {
const indexOfToken = url.indexOf("&token=")
const token = url.slice(indexOfToken + 7)
images.push({
"imageUrl": url,
"imageToken": token
});
this.setState({
images,
event,
isLoading: false,
});
// console.log(this.state.images)
})
.catch((error) => {
switch (error.code) {
case 'storage/object-not-found':
break;
case 'storage/unauthorized':
break;
case 'storage/canceled':
break;
case 'storage/unknown':
break;
}
});
});
}).catch((error) => {
});
}
onLongPress = (event) => {
if (event.nativeEvent.state === State.ACTIVE) {
alert("I've been pressed for 800 milliseconds");
}
};
render() {
if (this.state.isLoading) {
return (<Center style={styles.container} _dark={{ bg: "blueGray.900" }} _light={{ bg: "blueGray.50" }}>
<ActivityIndicator size="large" color="#22d3ee" />
</Center>
)
} else {
return (
<SafeAreaView style={styles.container} >
<FlatList _dark={{ bg: "blueGray.900" }} _light={{ bg: "blueGray.50" }}
style={styles.list}
numColumns={2}
ListHeaderComponent={<EventGalleryHeader data={this.state.event} />}
data={this.state.images}
keyExtractor={item => item.imageToken}
renderItem={({ item }) => (
<LongPressGestureHandler
onHandlerStateChange={this.onLongPress}
minDurationMs={800}
>
<Image key={item.imageToken} style={{ marginRight: 2, marginTop: 2, width: '50%', opacity: 1 }} source={{ uri: item.imageUrl }} alt="Alternate Text" size="xl" />
</LongPressGestureHandler>
)}
/>
</SafeAreaView>
);
}
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
maxHeight: 450,
width: '100%',
height: 200,
overflow: 'hidden',
},
list: {
alignSelf: 'center',
},
gallery: {
flex: 1,
width: '100%',
flexDirection: 'row',
}
})
And again it shows how important it is to read the documentation properly beforehand and to look there first if you have any questions.
You can achieve the behavior I mentioned above with the following parameters.
loadingIndicatorSource link
Similarly to source, this property represents the resource used to render the loading indicator for the image, displayed until image is ready to be displayed, typically after when it got downloaded from network.
onLoad link
Invoked when load completes successfully.
onLoadEnd link
Invoked when load either succeeds or fails.
onLoadStart link
Invoked on load start.
Example: onLoadStart={() => this.setState({loading: true})}

How To Refresh a Screen in React Native?

I know similar questions have been asked here already, but I just can't get it to work! Im using iframe to embed a YouTube player in one of my screens (using Stack Navigator). I created an array with some YouTube Links/IDs, which are then being randomised and imported into the player, so each time I navigate to that particular screen, a random video starts playing! Now I want to add a 'play next video' button! I tried updating the screen 'key' and use different methods of forceUpdating the screen, but nothing seems to work right! Does anyone have an Idea?
Heres my code:
note that rn there is the playpause function in the 'next vid' button
import React, { useState, useCallback, useRef } from "react";
import { Button, View, Alert, Text } from "react-native";
import YoutubePlayer from "react-native-youtube-iframe";
import {NeuView, NeuButton} from 'react-native-neu-element';
import { set } from "react-native-reanimated";
//example vids
const videos = [
'iNQAp2RtXBw',
'AJqiFpAl8Ew',
'IdoD2147Fik',
]
const randomVideo = () =>
videos[Math.floor(Math.random() * videos.length)];
export default function FunnyVideos() {
const [playing, setPlaying] = useState(true);
const [videoId, setRandomVideoId] = useState(randomVideo());
function pauseOrPlay() {
return ((
setPlaying(!playing)
), []);
}
return (
<View alignItems = 'center' >
<NeuView style = {{marginTop: '15%'}} width = {330} height = {200} color = '#f2f2f2' borderRadius = {20} >
<View overflow = 'hidden' height = {169} style = {{position: 'relative', marginTop: 0}} justifyContent = 'center' alignContent = 'center' borderRadius = {10}>
<YoutubePlayer
height={'100%'}
width={300}
videoId = {videoId}
play = {playing}
/>
</View>
</NeuView>
<View flexDirection = 'row'>
<NeuButton style = {{marginTop: 60}} width = {250} height = {100} color = '#f2f2f2' title={playing ? "pause" : "play"} onPress = {pauseOrPlay} borderRadius = {20}>
<Text>
{playing ? "pause" : "play"}
</Text>
</NeuButton>
</View>
<NeuButton style = {{marginTop: 45}} width = {250} height = {100} color = '#f2f2f2' title={playing ? "pause" : "play"} onPress = {pauseOrPlay} borderRadius = {20}>
<Text>
Next Video
</Text>
</NeuButton>
</View>
);
}
Change the onPress of Next Video to () => setRandomVideoId(randomVideo())
I usually use RefreshControl, because it's simple and it can be used in other components like FlatList, ListView etc. For Example: <ScrollView contentContainerStyle={styles.scrollView} refreshControl={<RefreshControl refreshing={refreshing} onRefresh={yourFunctionHere} /> And you can read more in official docs here https://reactnative.dev/docs/refreshcontrol
I am using class component , use this.state for refresh screen,
Here is an example:
import React, { Component } from "react";
import { Button, View, Alert, Text } from "react-native";
import YoutubePlayer from "react-native-youtube-iframe";
import { NeuView, NeuButton } from 'react-native-neu-element';
import { set } from "react-native-reanimated";
const videos = [
'iNQAp2RtXBw',
'AJqiFpAl8Ew',
'IdoD2147Fik',
]
export default class FunnyVideos extends Component {
constructor(props) {
super();
this.state = {
playing: true,
videoId: videos[Math.floor(Math.random() * videos.length)],
}
}
componentDidMount = () => {
this.setState({ videoId: videos[Math.floor(Math.random() * videos.length)] });
}
pauseOrPlay() {
}
refresh = () => {
this.componentDidMount();
}
render() {
let { videoId } = this.state;
return (
<View alignItems='center' >
<NeuView style={{ marginTop: '15%' }} width={330} height={200} color='#f2f2f2' borderRadius={20} >
<View overflow='hidden' height={169} style={{ position: 'relative', marginTop: 0 }} justifyContent='center' alignContent='center' borderRadius={10}>
<YoutubePlayer
height={'100%'}
width={300}
videoId={videoId}
play={playing}
/>
</View>
</NeuView>
<View flexDirection='row'>
<NeuButton style={{ marginTop: 60 }} width={250} height={100} color='#f2f2f2' title={playing ? "pause" : "play"} onPress={this.pauseOrPlay} borderRadius={20}>
<Text>
{playing ? "pause" : "play"}
</Text>
</NeuButton>
</View>
<NeuButton style={{ marginTop: 45 }} width={250} height={100} color='#f2f2f2' title={playing ? "pause" : "play"} onPress={this.refresh()} borderRadius={20}>
<Text>
Next Video
</Text>
</NeuButton>
</View>
);
}
}

How to play video in reverse using react-native-video?

I want to play 15 sec video. Firstly,i want to play video in simple order, after 15 seconds i want to plat video in reverse order.
In the following code, i am fetching video from local file and play in react-native-video. I want to play video as Instagram boomerang option. I also tried seek option of react-native-video option as backward but its not working.Please help me to this.
Here is my code:-
import React, { Component } from 'react';
import Modal from 'react-native-modal';
import { Avatar, Button, Icon } from 'react-native-elements';
import ImagePicker from 'react-native-image-picker';
import Video from 'react-native-video';
export default class VideoPickAndUpload extends Component {
constructor(props) {
super(props);
this.state = {
videoUri : null,
paused : false,
repeat : false,
rate : 1,
volume : 1,
resizeMode : 'contain',
duration : 0.0,
currentTime : 0.0,
rateText : 0.0,
pausedText : 'Play',
controls : true,
playIcon : 'controller-paus'
};
}
//video Select from camera or gallery
onSelectVideo = () => {
ImagePicker.showImagePicker({title:'Select Video',
takePhotoButtonTitle : 'Make Video',
maxHeight:800,maxWidth:800,
mediaType:'video',cropping:true},
video => {
if(video.didCancel){
ToastAndroid.show('Video selecting
cancel',ToastAndroid.LONG);
} else if(video.error){
ToastAndroid.show('Video selecting error :
'+video.error,ToastAndroid.LONG);
}else {
ToastAndroid.show('Video path :
'+video.uri,ToastAndroid.LONG);
this.setState({videoUri : video.uri})
}
}
)
}
//reset Video
onResetVideo = () => {
this.setState({videoUri : null})
}
onPress = () => {
if(this.state.paused == true){
this.setState({paused:false,playIcon:'controller-
paus'})
}else {
this.setState({paused:true,playIcon:'controller-play'})
}
}
//load video
onLoad = (data) => {
this.setState({duration : data.duration})
}
//load current progress
onProgress = (data) => {
this.setState({currentTime : data.currentTime})
ToastAndroid.show("Progress :
"+data.currentTime,ToastAndroid.LONG);
if(this.state.currentTime >= 15){
for(let i=data.currentTime;i>=1;i--){
this.video.seek(data.currentTime - i )
ToastAndroid.show("decrease :
"+i,ToastAndroid.LONG);
}
}
}
//when reach on end
onEnd = () => {
this.setState({pausedText : 'Play' , playIcon:'controller-
stop'})
//this.video.seek(0)
ToastAndroid.show("End :
"+this.state.currentTime,ToastAndroid.LONG);
}
//get current time percentage on progress bar
getCurrentTimePercentage() {
if(this.state.currentTime > 0){
return parseFloat(this.state.currentTime) /
parseFloat(this.state.duration)
}
return 0;
};
render() {
const {modalVisible,modalClose} = this.props;
return (
<Modal
animationIn={"bounceInRight"}
animationOut={"bounceOutRight"}
animationInTiming={500}
animationOutTiming={500}
isVisible={modalVisible}
onBackButtonPress={modalClose}
>
<View style={styles.container}>
<TouchableWithoutFeedback
onPress={() => this.onPress()}
style={{borderWidth:2,borderColor:'grey'}}
>
<Video
ref={ref => {this.video = ref}}
source={{uri: this.state.videoUri}}
style={{height:400,width:400}}
repeat={this.state.repeat}
rate={this.state.rate}
volume={this.state.volume}
resizeMode={this.state.resizeMode}
paused={this.state.paused}
onLoad={this.onLoad}
onProgress={this.onProgress}
onEnd={this.onEnd}
controls={this.state.controls}
playWhenInactive={true}
/>
</TouchableWithoutFeedback>
<View style =
{{margin:16,flexDirection:'row'}}>
<Icon
name='controller-fast-backward'
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() =>
{this.video.seek(this.state.currentTime-10)}}
/>
<Icon
name={this.state.playIcon}
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() => this.onPress()}
/>
<Icon
name='controller-fast-forward'
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() =>
{this.video.seek(this.state.currentTime+10)}}
/>
</View>
<View style =
{{margin:16,flexDirection:'row'}}>
<Button
title="Upload Video"
buttonStyle =
{{paddingHorizontal:16,paddingVertical:4}}
containerStyle = {{marginRight:8}}
onPress={()=>this.onSelectVideo()}
/>
<Button
title="Reset Video"
buttonStyle =
{{paddingHorizontal:16,paddingVertical:4}}
containerStyle = {{marginLeft:8}}
onPress={() => this.onResetVideo()}
/>
</View>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#212',
},
});
Use react-naitive-video-processing library for boomerang video.

React Native: performant rendering of an image based newsfeed

What are the best practices for rendering an image based newsfeed in react native?
I've got a very simple newsfeed where each story has a cover image and then a star rating (composed of 1-5 images). On initial render, the images appear to be loaded in random order and it looks awful and non-native.
Here's a 7s video showing the screen transition and render.
Is there any way to control the order in which the images render, or not to render a story until the whole block is loaded?
If it helps, the code is below. Using IncrementalListView to render the rows. Release build, iOS 9.3, iPhone 6. Each cover image is ~55kb JPG, and the star is ~3kb PNG. Both images are packaged into the bundle.
UPDATE 3/31
I changed the code to use IncrementalListView instead of rendering directly into ScrollView, but this hasn't helped. The problem seems to be with how images are decoded and rendered, not with how rows are rendered.
class DiscoverRow extends React.Component {
render() {
let images = {
wide: {
data: require('../img/img-wide.jpg'),
height: 200,
width: 376
}
};
let title = this.props.event.name;
let date = "Tomorrow";
let place = this.props.event.venue.name;
const newHeight = images.wide.height / images.wide.width * screenWidth;
return (
<View style={[rowStyles.cell]}>
<View style={{ borderRadius: 15 }}>
<Image resizeMode={'stretch'} source={images.wide.data} style={[rowStyles.thumbnail]} />
<View style={[rowStyles.annotationsContainer]}>
<View style={rowStyles.textContainer}>
<AHStarRating starColor={gConstants.themeColor} disabled rating={4.5} style={{ width: 100 }} />
<AHText style={rowStyles.title}>{title}</AHText>
<AHText style={rowStyles.date}>{date}</AHText>
</View>
<View style={rowStyles.commentsContainer}>
<Image source={require('../img/chat.png')}
style={{ width: 36, height: 36,
tintColor: gConstants.themeColor,
backgroundColor: 'transparent' }}
/>
<TouchableWithoutFeedback onPress={this._poop}>
<Image
source={require('../img/heart.png')}
style={{ width: 36, height: 36,
tintColor: gConstants.themeColor,
backgroundColor: 'transparent' }}
/>
</TouchableWithoutFeedback>
</View>
</View>
</View>
</View>
);
}
}
class DiscoverPage extends React.Component {
static relay = {
queries: { viewer: () => Relay.QL`query { viewer }` },
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
events {
id
name
venue {
name
}
}
}
`,
},
};
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.setState({ renderPlaceholderOnly: false });
});
}
componentWillReceiveProps(nextProps) {
if (!nextProps.relayLoading) {
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.setState({
dataSource: ds.cloneWithRows(nextProps.viewer.events),
});
}
}
_renderRow(event: Object, sectionID: number, rowID: number) {
return <DiscoverRow
onPress={() => Actions.event({ event })}
key={`comment-${rowID}`} event={event}
/>;
}
render() {
if (this.props.relayLoading || this.state.renderPlaceholderOnly) {
return <View><AHText>Relay loading</AHText></View>;
} else {
return (
<View style={styles.container}>
<AHNavBar title={'Discover'} leftTitle={""} rightImage={require('../img/filter.png')} />
<IncrementalListView
initialListSize={3}
dataSource={this.state.dataSource}
renderRow={this._renderRow}
renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`}
style={styles.separator} />}
/>
</View>
);
}
}
}
You should implement with a ListView instead of a ScrollView. ListView has performance optimizations that improve scrolling performance.
From the ListView section in the React Native Docs:
There are a few performance operations designed to make ListView
scroll smoothly while dynamically loading potentially very large (or
conceptually infinite) data sets

Categories