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>
);
}
}
Related
I am working on a React Native Project, I want to move the label along with the slider value. I tried many ways but its not working accurately.
Here is my code:
import React, { useState } from 'react'
import { Text, StyleSheet, View, Dimensions } from 'react-native'
import Slider from '#react-native-community/slider';
function LabelSlider() {
const windowWidth = Dimensions.get('window').width;
const [value, setValue] = useState(0)
// const left = value * (windowWidth-60)/85;
const [showValue, setShowValue] = useState(false)
//var percent = (percentToGet / 100) * number;
return (
<View>
{showValue ?
<View >
<Text style={{ width:50, textAlign: 'auto', left: value}}>{value}</Text>
</View> :
<></>}
<Slider
style={{ width: 200, height: 40 }}
maximumValue={300}
minimumValue={0}
step={1}
value={value}
onValueChange={(value) => setValue(value)}
onSlidingStart={() => setShowValue(true)}
onSlidingComplete={() => setShowValue(true)}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
/>
</View>
)
}
export { LabelSlider }
I have also attached two images of the output I was able to get:
Image 1,
Image 2
You can use a shared value and interpolate the left position for the label.
Right now what happens is, that the left value goes from 0 to 300. This makes the label unresponsive. You can do something as shown below.
Also, here's a Snack for the implementation.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Slider from '#react-native-community/slider';
import Animated, {
useSharedValue,
useAnimatedStyle,
interpolate,
Extrapolate,
} from 'react-native-reanimated';
// Constants
const MAX_SLIDER_VALUE = 300;
const MIN_SLIDER_VALUE = 0;
const SLIDER_WIDTH = 200;
export default function App() {
// State to store progress value of slider
const [value, setValue] = React.useState(0);
// Shared value for storing label position
const progress = useSharedValue(0);
// Whenever `value` changes, update the progress shared value
// This will accordingly update the left position of the label
React.useEffect(() => {
progress.value = value;
}, [value]);
// Animate the left position according to the shared value
// Also Extrapolate it so that it doesn't exceed 100%
const animatedStyle = useAnimatedStyle(() => {
const leftPosition = interpolate(
progress.value,
[MIN_SLIDER_VALUE, MAX_SLIDER_VALUE],
[0, 100],
Extrapolate.CLAMP
);
return {
left: `${leftPosition}%`,
};
});
return (
<View style={styles.container}>
<View style={{ width: SLIDER_WIDTH }}>
<Animated.View style={[styles.labelView, animatedStyle]}>
<Text>{value}</Text>
</Animated.View>
<Slider
style={{ width: SLIDER_WIDTH, height: 40 }}
maximumValue={MAX_SLIDER_VALUE}
minimumValue={MIN_SLIDER_VALUE}
step={1}
value={value}
onValueChange={setValue}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
labelView: {
marginBottom: 20,
},
});
You can use react native element slider for this, I have given the example code below
import React from 'react';
import { View } from 'react-native';
import {Slider} from 'react-native-elements';
const App = () => {
return (
<View
style={{
flex: 1,
justifyContent: "center",
}}>
<Slider
thumbStyle={{height: 15, width: 15, backgroundColor: 'orange'}}
maximumTrackTintColor="grey"
minimumTrackTintColor="orange"
thumbProps={{
children: (
<View
style={{
color: 'green',
marginTop: -22,
width: 100,
}}>
<Text>Value</Text>
</View>
),
}}
/>
</View>
)
}
export default App;
Been using Expo and RN on an app, but I'm stuck with a problem. I'm using Expo Video
to make a photo/video gallery. The problem is, if I have more than 1 video in the array, only the last one will play (problem with useRef). And I couldn't find a way to create a ref for each one of them.
Solutions that I've tried and half worked: I created a VideoComponent (as a function then added on return), and each component had its own useRef and useState for playing inside the component a different useRef/useState for video/status for each. It worked okay-ish. But the problem was when other states changed (user presses like, for example). Whenever a state changes, and rerenders, the whole video reset to the beginning. Which is not ok.
The video reset on state change of other components doesn't affect the video if doing it normally (one useRef/state) but as I said, It's only playing the last component, which is not okay.
import React, { useRef, useState } from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
} from 'react-native';
function App(props) {
const [allData, setAllData] = useState([
{
medias: [
{ link: 'https://link.com/link1.avi', mediaExtension: 'avi' },
{ link: 'https://link.com/link2.jpg', mediaExtension: 'jpg' },
{ link: 'https://link.com/link3.mov', mediaExtension: 'mov' },
],
name: 'Name',
description: 'description',
},
]);
const video = useRef(null);
const [status, setStatus] = useState({});
return (
<View style={{}}>
<FlatList
horizontal
data={allData}
renderItem={({ item }) => (
<View style={{}}>
{item.medias.map((item) => (
<View>
{item.mediaExtension === 'mov' || 'avi' || 'WebM' ? (
<View style={{ flex: 1 }}>
<TouchableOpacity
onPress={() =>
video.isPlaying
? video.current.pauseAsync()
: video.current.playAsync()
}>
<Video
ref={video}
style={{ alignSelf: 'center' }}
source={{
uri: item.link,
}}
onPlaybackStatusUpdate={(status) =>
setStatus(() => status)
}
/>
</TouchableOpacity>
</View>
) : (
<Image style={{}} source={{ uri: item.link }} />
)}
</View>
))}
</View>
)}
/>
</View>
);
}
export default App;
As far as I understand, you want to create a FlatList of Videos, and onScroll you want to pause it. This can be implemented as shown below
Also, here is a Working Example for this
import * as React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import VideoPlayer from './components/VideoPlayer';
const Videos = [
{
_id: 1,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 2,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 3,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 4,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 5,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 6,
source: require('./assets/videoplayback.mp4'),
},
];
export default function App() {
const [Viewable, SetViewable] = React.useState([]);
const ref = React.useRef(null);
const onViewRef = React.useRef((viewableItems) => {
let Check = [];
for (var i = 0; i < viewableItems.viewableItems.length; i++) {
Check.push(viewableItems.viewableItems[i].item);
}
SetViewable(Check);
});
const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 80 });
return (
<View style={styles.container}>
<FlatList
data={Videos}
keyExtractor={(item) => item._id.toString()}
renderItem={({ item }) => <VideoPlayer {...item} viewable={Viewable} />}
ref={ref}
onViewableItemsChanged={onViewRef.current}
viewabilityConfig={viewConfigRef.current}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
and VideoPLayer component looks like this
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import { Video, AVPlaybackStatus } from 'expo-av';
export default function VideoPlayer({ viewable, _id, source }) {
const video = React.useRef(null);
React.useEffect(() => {
if (viewable) {
if (viewable.length) {
if (viewable[0]._id === _id) {
video.current.playAsync();
} else {
video.current.pauseAsync();
}
} else {
video.current.pauseAsync();
}
} else {
video.current.pauseAsync();
}
}, [viewable]);
return (
<View style={styles.container}>
<Video
ref={video}
source={source}
rate={1.0}
volume={1.0}
resizeMode={'contain'}
isLooping
shouldPlay
style={styles.video}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
width: Dimensions.get('window').width,
marginBottom: 100,
marginTop: 100,
},
video: {
width: Dimensions.get('window').width,
height: 300,
},
});
So when I use this code everything works just fine:
import * as React from 'react';
import { Button, Image, View, TouchableOpacity, StyleSheet, TouchableWithoutFeedback, KeyboardAvoidingView, SimpleAnimation, Text, TextInput} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import { Ionicons } from '#expo/vector-icons';
import FlatButton from './button';
const thirdColor = 'red';
const secColor = 'blue';
const mainColor = 'green';
export default class ImagePickerExample extends React.Component {
state = {
image: null,
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Pick an image from camera roll"
onPress={this._pickImage}
/>
{image &&
<Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
</View>
);
...
After that, everything I change is inside my redner() method and the code looks so:
...
export default class ImagePickerExample extends React.Component {
state = {
image: null,
};
render() {
let { image } = this.state;
return (
<TouchableWithoutFeedback onPress={() => {
//whenever touched the soroundings, keyboard will be dismissed
Keyboard.dismiss();
}}>
<View style={styles.container}>
<KeyboardAvoidingView behavior='position'>
<SimpleAnimation delay={500} duration={1200} fade staticType='bounce'>
<Text style={{color: thirdColor, fontSize: 61}}>Welcome back</Text>
</SimpleAnimation>
{image &&
<TouchableOpacity onPress={this._pickImage}>
<Ionicons name="ios-person" size={100} color={thirdColor} ></Ionicons>
</TouchableOpacity>}
<SimpleAnimation delay={600} duration={1200} fade staticType='bounce'>
<View style={styles.contYourName}>
<TextInput placeholder='Username' style = {styles.yourName}></TextInput>
</View>
</SimpleAnimation>
<SimpleAnimation delay={900} duration={1200} fade staticType='bounce'>
<View style={styles.regButtonView}>
<FlatButton text='finsih' onPress={alert}/>
</View>
</SimpleAnimation>
</KeyboardAvoidingView>
</View>
</TouchableWithoutFeedback>
);
}
...
After I did this I get following error message on my iPhone through Expo:
error code from IOS
What is wrong with it? My current React Native version is:
react-native-cli: 2.0.1
react-native: 0.61.4
EDIT:
Here are the functions:
componentDidMount() {
this.getPermissionAsync();
console.log('hi');
}
getPermissionAsync = async () => {
if (Constants.platform.ios) {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
}
}
_pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1
});
console.log(result);
if (!result.cancelled) {
this.setState({ image: result.uri });
}
};
Another EDIT:
As soon as I comment all <SimpleAnimation></SimpleAnimation> than everything works again. Why is <SimpleAnimation></SimpleAnimation> a problem?
change image state to "" (empty String) instead of null or handle null condition of image uri;
import * as React from 'react';
import { Button, Image, View, TouchableOpacity, StyleSheet, TouchableWithoutFeedback, KeyboardAvoidingView, SimpleAnimation, Text, TextInput} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import { Ionicons } from '#expo/vector-icons';
import FlatButton from './button';
const thirdColor = 'red';
const secColor = 'blue';
const mainColor = 'green';
export default class ImagePickerExample extends React.Component {
state = {
image: "",
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Pick an image from camera roll"
onPress={this._pickImage}
/>
{image &&
<Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
</View>
);
Check all methods are imported which you have used.
use this.state.image instead of image.
Rerun or reload
So the problem was the <SimpleAnimation></SimpleAnimation> tags in my render(). Thats because somehow this import got messed up. So I did the following that fixed my problem:
npm uninstall react-native-simple-animations
npm install react-native-simple-animations
After that import in your code with: import { SimpleAnimation } from 'react-native- simple-animations'; dont forget the { }
is it possible to render a React.Component over other React.Component using just fat arrow function, using state seems unnecessary in my case as there is no need to close the opened Component. I am trying to achieve the simplest to render a React.Component over other React.Component.
I am trying to do it like this:
<Button onPress={() => { return (<ShowOtherReactComponent/>); }} >Show OtherComponent</Button>
this is calling the <ShowOtherReactComponent/> I know that because I called an alert function from constructor but! nothing is rendering. why is that? how can I do this?
PS: this approach may be wrong, but still wanna see how it can be done. for science.
You shouldn't return jsx from your handlers. Usually to show and or toggle components conditional rendering is the way to go.
Instead of returning <ShowOtherReactComponent/> from onPress you conditionally render the component based on a boolean binded to the local state and change the state instead.
const Component = () =>{
const [show, setShow] = useState(false)
const onPress = () => setShow(true)
return(
<>
<button onPress={onPress}> Show </button>
{ show && <ShowOtherReactComponent/> }
</>
)
}
I've made an example to show what you could potentially do if you wanted a button to add components to display:
import React from 'react';
import autoBind from 'react-autobind';
export default class ButtonTest extends React.Component {
constructor(props) {
super(props);
this.state = {
extraComponents : []
};
autoBind(this);
}
addComponent() {
const newComponent = (<p>I'm a new component</p>);
this.setState({extraComponents: [...this.state.extraComponents, newComponent]})
}
render() {
return (
<div>
<button onClick={this.addComponent}>add component</button>
{this.state.extraComponent}
</div>
)
}
}
I've checked it and it works.
import React, { useState } from 'react'
import { SafeAreaView, View, Text, Button, Dimensions } from 'react-native'
const App = () => {
const [visibilityOfOtherView, setvisibilityOfOtherView] = useState(false)
const { height, width } = Dimensions.get('window')
const SCREEN_HEIGHT = Math.round(height)
const SCREEN_WIDTH = Math.round(width)
return (
<SafeAreaView style={{ height: SCREEN_HEIGHT, width: SCREEN_WIDTH, }}>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'red' }}>
<Text style={{ marginBottom: 20 }}>
First Components
</Text>
<Button
title='Toggle Components View'
onPress={() => setvisibilityOfOtherView(!visibilityOfOtherView)}
/>
</View>
{
visibilityOfOtherView ?
<View style={{ height: SCREEN_HEIGHT, width: SCREEN_WIDTH, alignItems: 'center', justifyContent: 'center', backgroundColor: 'green' }}>
<Text style={{ marginBottom: 20 }}>
Secound Components
</Text>
<Button
title='Toggle Components View'
onPress={() => setvisibilityOfOtherView(!visibilityOfOtherView)}
/>
</View>
: null
}
</SafeAreaView>
)
}
export default App
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.