React native camera not recording video - reactjs

I want to implement the video recording feature using react native video but the start recording function is not giving any response, I even consoled to see whether it is getting called,actually it is not, am unable to figure what I have done wrong.
Below is the exact code that I have written
import React from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
} from 'react-native';
import {RNCamera} from 'react-native-camera';
export default class Shoot extends React.Component {
constructor(props) {
super(props);
this.state = {
recording: false,
processing: true,
};
}
async startRecording() {
this.setState({recording: true});
// default to mp4 for android as codec is not set
const {uri, codec = 'mp4'} = await this.camera.recordAsync();
}
stopRecording = () => {
this.camera.stopRecording();
};
render() {
const {recording, processing} = this.state;
let button = (
<TouchableOpacity
onPress={this.startRecording.bind(this)}
style={styles.capture}>
{console.log('aaa')}
<Text style={{fontSize: 14}}> RECORD </Text>
</TouchableOpacity>
);
if (recording) {
button = (
<TouchableOpacity
onPress={this.stopRecording.bind(this)}
style={styles.capture}>
<Text style={{fontSize: 14}}> STOP </Text>
</TouchableOpacity>
);
}
if (processing) {
button = (
<View style={styles.capture}>
<ActivityIndicator animating size={18} />
</View>
);
}
return (
<View style={styles.container}>
<RNCamera
ref={(ref) => {
this.camera = ref;
}}
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.on}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={
'We need your permission to use your camera phone'
}
/>
<View style={{flex: 0, flexDirection: 'row', justifyContent: 'center'}}>
{button}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
},
capture: {
flex: 0,
backgroundColor: '#e75480',
borderRadius: 40,
width: 80,
height: 80,
paddingHorizontal: 20,
alignSelf: 'center',
margin: 20,
},
});
so here, the button touchability onpress which is startRecording is not getting called at all.
Any help would be great, thank you

I still could not figure what went wrong with the above code but using react-native-beautiful-video-recorder as the package, I finally found the app to behave as per my requirements.
If anybody meets with the same issue, it is better to use react-native-beautiful-video-recorder.

Try onPress with arrowed function
<TouchableOpacity
onPress={() => this.startRecording()}
style={styles.capture}>
{console.log('aaa')}
<Text style={{fontSize: 14}}> RECORD </Text>
</TouchableOpacity>
And bind this
constructor(props) {
super(props);
this.state = {
recording: false,
processing: true,
};
this.startRecording = this.startRecording.bind(this)
}

render() {
const {recording, processing} = this.state;
let button;
if (recording) {
button = (
<TouchableOpacity
onPress={this.stopRecording.bind(this)}
style={styles.capture}>
<Text style={{fontSize: 14}}> STOP </Text>
</TouchableOpacity>
);
}
else if (processing) {
button = (
<View style={styles.capture}>
<ActivityIndicator animating size={18} />
</View>
);
}
else {
button = (
<TouchableOpacity
onPress={this.startRecording.bind(this)}
style={styles.capture}>
{console.log('aaa')}
<Text style={{fontSize: 14}}> RECORD </Text>
</TouchableOpacity>
);

The issue you are dealing with is much simpler than you think
your initial state is this one
this.state = {
recording: false,
processing: true,
};
so the button then renders if processing and recording are false ,
the initial button starts the video,
so your initial state must be this one
this.state = {
recording: false,
processing: false,
};

Related

How to make independent style change on React mapped component

I have problem when I try to change the style of a mapped TouchableOpacity.
I map a list of TouchableOpacity and I would like that when I click on one, the backgroundColor change (in black) only on the on I clicked but also to reset the backgroundColor of the other TouchableOpacity I clicked before.
So for example, if I click on the first TouchableOpacity the background of that one become black. And after, if I click on the second, the background of the second become black but the background of the first become again grey.
export default class Playground extends Component {
state = {
isPressed: false
};
handlePress = () => {
this.setState({
isPressed: !this.state.isPressed
});
};
render() {
let array = [0, 1, 2];
return (
<View style={styles.container}>
<Text>Test</Text>
{array.map(item => {
return (
<TouchableOpacity
key={item}
style={this.state.isPressed ? styles.buttonPressed : styles.button}
onPress={this.handlePress}
>
<Text>Click on it</Text>
</TouchableOpacity>
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
marginTop: 50
},
button: {
backgroundColor: 'grey'
},
buttonPressed: {
backgroundColor: 'black'
}
});
This is what I tried but when I click on one TouchableOpacity the backgroundColor of all of them change.
I would like to target only one and reset the other in the same time
it's good working
[import React, { Component } from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
export default class Playground extends Component {
state = {
isPressed: false
};
handlePress = () => {
this.setState({
isPressed: !this.state.isPressed
});
};
render() {
let array = \[0, 1, 2\];
return (
<View style={styles.container}>
<Text>Test</Text>
{array.map(item => {
return (
<TouchableOpacity
key={item}
style={this.state.isPressed === false ? styles.buttonPressed : styles.button}
onPress={this.handlePress}
>
<Text>Click on it</Text>
</TouchableOpacity>
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
marginTop: 50
},
button: {
backgroundColor: 'grey'
},
buttonPressed: {
backgroundColor: 'black'
}
});
Not sure if it's the best way to resolve the problem, but I find a potential solution using direct manipulation
I start by assigning a different reference to each TouchableOpacity and after I target that ref and use setNativeProps to change the style of the target
export default class Playground extends Component {
state = {
daySelected: null
}
handlePress = (day, i) => {
if (this.state.daySelected !== null) {
this.state.daySelected.setNativeProps({
backgroundColor: 'grey'
});
}
this.setState({
daySelected: day
});
day.setNativeProps({
backgroundColor: 'black'
});
};
render() {
let array = [0, 1, 2];
return (
<View style={styles.container}>
<Text>Test</Text>
{array.map(i => {
return (
<TouchableOpacity
key={i}
ref={thisItem => (this[`item-${i}`] = thisItem)}
style={styles.button}
onPress={() => this.handlePress(this[`item-${i}`], i)}
>
<Text>Click on it</Text>
</TouchableOpacity>
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
marginTop: 50
},
button: {
backgroundColor: 'grey'
}
});

How to get a user’s choice with onPress props in React Native

Good day everyone. please what is React Native’s replacement of React’s e.target.innerText? I’m trying to get what a user click on from TouchableOpacity component. I’m building a React Native quiz app.
I used TouchableOpacity for the options. I’m using onPress function to get the options the user clicks on with
<View style={{ flex: 2, flexDirection: 'row', justifyContent: 'space-between' }}>
<TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
<View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
<Text style={styles.options}>{questions[currentQuestion].options[0]}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
<View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
<Text style={styles.options}>{questions[currentQuestion].options[1]}</Text>
</View>
</TouchableOpacity>
</View>
<View style={{ flex: 2.7, flexDirection: 'row', justifyContent: 'space-between' }}>
<TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
<View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
<Text style={styles.options}>{questions[currentQuestion].options[2]}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress = {(e)=>this.props.onAnswer(e, currentQuestion)}>
<View style={{ width: 171.5, height: 100, backgroundColor: 'lightgrey' }}>
<Text style={styles.options}>
{questions[currentQuestion].options[3]}
</Text>
</View>
</TouchableOpacity>
</View>
So creating the answer function ... how do I determine if the user has chosen the correct answer.
onAnswer = () => {
return (
??? === questions[currentQuestion].answer ? this.onCorrect() : this.onWrong()
)
}
If it was React,I'd have replaced the '???' to e.target.innerText
Please help me out here.
EDIT:
My original answer below is similar to what you have. So just simply edit your onPress method like this:
onPress = {(e)=>this.props.onAnswer(currentQuestion, questions[currentQuestion].options[0])}
and your onAnswer will be able to take the users answer per questions:
onAnswer(question, usersAnswer) {
..
}
render() { ... }
**
Mostly, react components should be driven by data or states and props (you don't want to work with your logic by relying to DOM elements with pure JS or JQuery).
For that, you want a react solution like below:
...
state = {
data: [{
id: 1,
name: 'Anna'
},
{
id: 2,
name: 'John'
},
{
id: 3,
name: 'James'
},
{
id: 4,
name: 'John'
}]
}
onPersonPress(person) {
console.log("e is ", person);
}
render() {
const { data = [] } = this.state;
return (
<View>
{data.map(person => {
return (<TouchableOpacity onPress={(e) => this.onPersonPress(person)}>
<View><Text>Click Me - {person.name}</Text></View>
</TouchableOpacity>)
})}
</View>
)
}
...
The reason why this is the most common way to deal with this kind of problem is because of it's flexibility and probably it's the most logical. With this, you can use the identifier (id) or any field instead of being forced to what Text displays 'innerText' which isn't always unique (in my case there's another John)
P.S: Others don't like this implementation because of performance considerations onPress={(e) => this.onPersonPress(person)} so there are other ways to achieve the same.
Try this:
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const questions = [
{
question: 'question1 ?',
options: ['option1', 'option2', 'option3'],
answer: 'option2',
score: 10,
},
{
question: 'question2 ?',
options: ['option1', 'option2', 'option3'],
answer: 'option1',
score: 10,
},
{
question: 'question3 ?',
options: ['option1', 'option2', 'option3'],
answer: 'option3',
score: 10,
},
];
class QuizQuestion extends React.Component {
constructor(props) {
super(props);
this.state = {
totalScore: 0,
answered: questions.map(() => false), // All questions' answered state = false at statup
};
}
render() {
return (
<View
style={{
flex: 2,
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
{questions.map(({
question, options, answer, score,
}, index) => (
<View>
<View>
<Text>{question}</Text>
</View>
{/* Options */}
<View>
{options.map(({ option }) => (
<TouchableOpacity
onPress={() => {
let { totalScore, answered } = this.state;
if (!answered[index] && option === answer) {
answered[index] = true;
this.setState({
totalScore: totalScore + score,
answered,
});
}
}}
>
<View>
<Text>{option}</Text>
</View>
</TouchableOpacity>
))}
</View>
</View>
))}
</View>
);
}
}

React Native Modal not showing up

I am trying to show a modal without going to another screen, I want it to be displayed on the current screen but not through navigation. The modal doesn't pop up and I don't know the problem.
I am using the renderModal to show the modal on the screen.When I use this.props.navigation.navigate('AnotherModal'), it works but goes to another screen,this time I want to show modal on the same screen.
import * as React from 'react';
import { Text, View, Image,
StyleSheet,Alert,Modal,TouchableHighlight } from 'react-native';
import { Constants } from 'expo';
import { Appbar, Colors, FAB } from 'react-native-paper';
import ProductsModal from './ProductsModal';
import ModalTester from './ModalTester';
export default class AppBar extends React.Component {
state = {
modalVisible: false,
};
setModalVisible(visible)
{
this.setState({modalVisible: visible});
}
renderModal() {
return (
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.appbar}>
<Appbar style={styles.piece}>
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={this.renderModal.bind(this)}
/>
</Appbar>
<View>
<Image
source={require('../../assets/cutout.png')}
style={styles.cutout}
pointerEvents="none"
/>
<FAB
icon={require('../../assets/add_circle.png')}
color="#b2beb5"
onPress={() => navigate('Homes')}
style={styles.fab} />
</View>
<Appbar style={[styles.piece, styles.right]}>
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
//backgroundColor: '#ecf0f1',
padding: 8,
},
appbar: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 56,
flexDirection: 'row',
},
piece: {
flex: 1,
backgroundColor: Colors.grey300,
},
right: {
justifyContent: 'flex-end',
},
cutout: {
height: 56,
width: 80,
tintColor: Colors.grey300,
},
fab: {
position: 'absolute',
margin: 12,
bottom: 16
}
});
You should try to bind your setModalVisible in the constructor first:
constructor(props) {
super(props);
this. setModalVisible = this. setModalVisible.bind(this);
}
And then change your first Appbar.Action to something like this:
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={() => this. setModalVisible(true)}
/>
Also you have to add your Modal to the rendered code
...
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
{this.renderModal()}
</View>
I'm not sure the bind is necessary though
Since screen does not change, your Modal needs to be within the render method of that screen. This means it can be handled by the state of the component. For example to show it you can:
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={() => this.setModalVisible(true)}
/>
In the main render you can just add directly your renderModal, 'cause its visible prop is sufficient to handle the behavior:
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.appbar}>
<Appbar style={styles.piece}>
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={this.renderModal.bind(this)}
/>
</Appbar>
<View>
{this.renderModal()}
<Image
source={require('../../assets/cutout.png')}
style={styles.cutout}
pointerEvents="none"
/>
<FAB
icon={require('../../assets/add_circle.png')}
color="#b2beb5"
onPress={() => navigate('Homes')}
style={styles.fab} />
</View>
<Appbar style={[styles.piece, styles.right]}>
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
</View>
);
}

How to Open React Native Expo Camera On Button Click

Here is the code for the camera. I want a button to open the camera. I don't want it to automatically open on app startup. Also is there any way to detect text in the image and save it?
import React from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera, Permissions } from 'expo';
export default class CameraExample extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Text
style={{ fontSize: 18, marginBottom: 10, color: 'white' }}>
{' '}Flip{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
You can put your view in a variable and render it on button press. In my camera I've done this for an image preview when the photo is taken:
if (BUTTON PRESS CONDITION) {
imageView = (
<View style={styles.previewContainer}>
<Image style={styles.imagePreview} source={{uri: `data:image/gif;base64,${base64Post}`}} />
<View style={styles.container}>
<TouchableOpacity style={styles.sendButton} onPress={() => Alert.alert("Not implemented!")}>
<Image style={{width: 70, height: 70}} source={require('../assets/Send.png')}/>
</TouchableOpacity>
</View>
<View style={styles.container} key={this.state.uniqueValue}>
<TouchableOpacity style={styles.undoButton} onPress={() => this.setState({ persist64: null})}>
<Image style={{width: 70, height: 70}} source={require('../assets/undoButton.png')}/>
</TouchableOpacity>
</View>
</View>
)
}
You could set up some boolean that when you press the button it is true renders the view of your camera. Then take the name of the view you made and put it somewhere in your render. like so:
{imageView}
If you need further explanation let me know.
Alternatively you could just create a separate page for your camera and have a button that navigates to the camera page.
You can simply connect the button and navigate to the camera on click. It is the very standard of navigating in both react or react native.. So just use whatever navigation library youre using, and use the nav props to redirect to camera onPress().

how to add keys in this project

im using react o nexpo xde and when i run the project i get a warning because my list doesnt hae keys, i want to know where and how to assing them, this is my code
import React, { Component } from 'react';
import { StyleSheet, Text, View,AppRegistry,Image,ActivityIndicator, FlatList,Navigator,TouchableHighlight, } from 'react-native';
import { StackNavigator } from 'react-navigation';
class Lista extends Component {
static navigationOptions = {
title: 'Lista',
}
constructor(props) {
super(props);
this.state = {
data:[]
};
}
load = async ()=>{
try{
let resp = await fetch('https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=fd829ddc49214efb935920463668608d')
let json = await resp.json()
this.setState({data:json.articles})
} catch (err) { console.log(err) }
}
componentDidMount(){this.load()}
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style={{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style={{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { item } = navigation.state;
return {
title: item ? item.date : 'Details Screen',
}
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Image source={{uri:this.props.navigation.state.params.item.urlToImage}} style={{width: 90, height: 80 }}/>
<Text>{this.props.navigation.state.params.item.title}</Text>
<Text>{this.props.navigation.state.params.item.publishedAt}</Text>
</View>
);
}
}
const RootStack = StackNavigator(
{
Lista: {
screen: Lista,
},
Details: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Lista',
}
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
i know it has to be something like, key={i} bu i hae tried in some ways and it doesnt work, im just learning react by myself so im a little confused here
ty so much
In your case you need to set up key to each child of <FlatList /> component. By react native docs recomended to use keyExtractor method defined in your component.
keyExtractor = (item, index) => index
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
keyExtractor={this.keyExtractor}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style= {{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style= {{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
I set just index of element as key, but you can set as you wont, but make sure it is unique. But using indexes is bad practice, it is not safe.

Resources