How to Open React Native Expo Camera On Button Click - reactjs

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().

Related

Why does nesting my modal in a MapView turn a 1 finger gesture into 3 finger gesture?

For context, what led me to this bug was trying to make it so my modal would disappear when tapping outside of the custom view inside the modal.
Using react-native-modal and what you see below, I achieved this goal. However, when I tried to overlay this modal on top of a map, I discovered it no longer worked unless I tapped with 3 fingers.
I have no idea why this occurs. I have an example here on snack expo so if you have the expo go app you can see for yourself. If you do not have the app, you can use the built in emulators but I am not sure you can recreate 3 simultaneous taps. Remove the MapView and you can see it works with a single tap.
How can I make it so it just takes a single finger tap rather than 3 simultaneous ones?
import MapView, { PROVIDER_GOOGLE, } from 'react-native-maps';
import Modal from "react-native-modal";
export default function App(){
const [hideModal, setHideModal] = React.useState(false)
return (
<View style={{...StyleSheet.absoluteFillObject}}>
<TouchableOpacity onPress={() => setHideModal(false)}>
<Modal isVisible={hideModal}>
<TouchableWithoutFeedback onPress={() => {}}>
<View style={{height: 200, width: 100, backgroundColor: 'red'}}></View>
</TouchableWithoutFeedback>
</Modal>
</TouchableOpacity>
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}>
<View style={{position: 'absolute', top: 100, left: 100}}>
<TouchableOpacity onPress={() => setHideModal(true)}>
<Text style={{fontWeight: 'bold', color: 'pink', fontSize: 26}}>Click me for modal</Text>
</TouchableOpacity>
</View>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject
},
})
try this
import * as React from 'react';
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import MapView from 'react-native-maps';
import Modal from 'react-native-modal';
export default function App() {
const [showModal, setShowModal] = React.useState(false);
return (
<View style={{flex: 1}}>
<Modal isVisible={showModal} onBackdropPress={() => setShowModal(false)}>
<View style={{height: 200, width: 100, backgroundColor: 'red'}} />
</Modal>
<MapView provider={undefined} style={styles.map}>
<View style={{position: 'absolute', top: 100, left: 100}}>
<TouchableOpacity onPress={() => setShowModal(true)}>
<Text style={{fontWeight: 'bold', color: 'pink', fontSize: 26}}>
Click me for modal
</Text>
</TouchableOpacity>
</View>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
});
Modal have onBackdropPress

React native camera not recording video

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

React Native Add Top thin header

hello I'm developing a react native app everything is fine but I have a problem
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<StatusBar
translucent={true}
backgroundColor={'rgba(0, 0, 0, 0.3)'}
barStyle={'light-content'}
/>
{ this.gradient }
<ScrollView
style={styles.scrollview}
scrollEventThrottle={200}
directionalLockEnabled={true}
>
{ carousel }
<FlatList
data={ this.state.GridListItems }
renderItem={ ({item}) =>
<TouchableOpacity
style={styles.GridViewContainer}
onPress={() => this.props.navigation.push('ProfileScreen', { height: "6'2", category: item.key })}>
<ImageBackground
source={{ uri: item.img }}
style={{width: '108%', height: '110%', justifyContent:'center'}}
>
<Text style={styles.GridViewTextLayout} > {item.key} </Text>
</ImageBackground>
</TouchableOpacity>
}
numColumns={2}
/>
</ScrollView>
</View>
</SafeAreaView>
);
styles
safeArea: {
flex: 1,
backgroundColor: colors.black
},
container: {
flex: 1,
backgroundColor: colors.background1
},
when I scroll down you see the mobile battery and wifi (top bar) is in the app
I want the app to be below the mobile topbar how can I achieve that?
here is an expo qr code
once try this and let me know your results:
import React,{Fragment} from 'react';
return (
<Fragment>
<SafeAreaView style={{ flex: 0, backgroundColor: 'red' }} />
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
{ this.gradient }
<ScrollView
style={styles.scrollview}
scrollEventThrottle={200}
directionalLockEnabled={true}
>
{ carousel }
<FlatList
data={ this.state.GridListItems }
renderItem={ ({item}) =>
<TouchableOpacity
style={styles.GridViewContainer}
onPress={() => this.props.navigation.push('ProfileScreen', { height: "6'2", category: item.key })}>
<ImageBackground
source={{ uri: item.img }}
style={{width: '108%', height: '110%', justifyContent:'center'}}
>
<Text style={styles.GridViewTextLayout} > {item.key} </Text>
</ImageBackground>
</TouchableOpacity>
}
numColumns={2}
/>
</ScrollView>
</View>
</SafeAreaView>
);
i added safeareaview (flex:0) for statusBar you can apply any color you want.
provide options in your navigator file as:
navigationName: {
screen: fileName,
navigationOptions: ({ navigation }) => {
if (Platform.OS === "android") {
return {
title: 'images',
headerStyle: {
backgroundColor: '#382464',
height: 50,
},
headerTitleStyle: {
color: '#fff',
},
headerTintColor: '#fff',
// header: props => <UriBar {...props} />
}
} else {
return {
header: null
}
}
}
},
you can also use statusBar for android
You should use SafeAreaView.
It will render your component without overlapping the "top bar".
import { SafeAreaView } from 'react-native'
...
return (
<SafeAreaView>
// your components
<SafeAreaView/>
)
Edit:
As you can see in the docs.
Simply wrap your top level view with a SafeAreaView with a flex: 1 style applied to it. You may also want to use a background color that matches your application's design.
So if you already using SafeAreaView, maybe you don't have flex: 1 and it's not working in the way you want.

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

Tap outside of modal to close modal (react-native-modal)

Anyone has experience of implementing react-native-modal?
While I'm using it, modal isn't closed when I tap outside of modal.
Here is what I've tried
Adding onBackdropPress(() => {this.props.hideModal()})
Adding TouchableWithoutFeedback inside and outside of components
and many other approaches...
Here is my the screen where I want to show my modal.
render() {
return (
<View style={{flex: 1}}>
<ScrollView>
// CONTENT HERE
{this._renderModal()} //rendering modal here
<FABs onFABsPress={this._showModal} /> // I open Modal when I press the FABs button
</ScrollView>
</View>
)
);
_renderModal = () => {
return (
<CameraImageSelectModal
hideModal={this._hideModal}
isModalVisible={this.state.isModalVisible}
navigation={this.props.navigation}
/>
)
}
Here is modal component : CameraImageSelectModal.js
render() {
let { isModalVisible } = this.props;
return (
<View>
<Modal
isVisible={isModalVisible}
onBackdropPress={() => {console.log('hey')}}>
transparent={true}>
<View style={styles.modalContainer}>
<View style={styles.modalTitleTextContainer}>
<Text style={styles.modalTitleText}>Hello World</Text>
</View>
<View style={styles.modalContentTextContainer}>
<Text style={styles.modalContentText}></Text>
</View>
<View style={styles.modalButtonContainer}>
<Button transparent onPress={this._handleCameraPress}>
<Text style={[styles.modalText, styles.black]}>Camera</Text>
</Button>
<Button transparent onPress={this._handleAlbumPress}>
<Text style={styles.modalText}>Album</Text>
</Button>
</View>
</View>
</Modal>
</View>
Thanks!!
I don't think the modal has that built in functionality, but you could create your own component that does. Here is a quick implementation. You might have to mess around with padding and margin to get it how you like, but this will allow the modal to be dismissed when pressing outside.
import React, { Component } from "react"
import { Modal, StyleSheet, View, TouchableHighlight } from "react-native"
const styles = StyleSheet.create({
container: {
zIndex: 1,
margin: 25,
backgroundColor: "white"
},
background: {
flex: 1
},
outerContainer: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: "center"
}
})
const MyModal = props => (
<Modal transparent={true} animationType={"slide"} visible={props.visible} onRequestClose={() => props.onRequestClose()}>
<TouchableHighlight style={styles.background} onPress={() => props.onRequestClose()} underlayColor={"transparent"}>
<View />
</TouchableHighlight>
<View style={ styles.outerContainer }>
<View style={styles.container}>
{props.children}
</View>
</View>
</Modal>
)
export { MyModal }
I just figured out why onBackdropPress = {() => console.log("Pressed")} didn't work..!!! onBackdropPress property was added since its version 3.xx and I was using 2.5.0 version.
So yarn update react-native-modal solved the issue.
If anyone encounters the problem that the library/component doesn't work as expected as you seen on documentation, try to check your package version number!
Cheers!
<Modal
isVisible={isModalVisible}
customBackdrop={
<View
style={styles.backDropContainer}
onTouchEnd={() => setModalVisible(false)}
/>
}
onBackdropPress={() => setModalVisible(false)}>
<View style={styles.modalContainer}>
<FlatList data={DATA} renderItem={() => <Text>hehehe</Text>} />
</View>
</Modal>
Style:
const styles = StyleSheet.create({
backDropContainer: {
flex: 1,
backgroundColor: 'black',
opacity: 0.5,
},
modalContainer: {
flex: 0.5,
backgroundColor: 'white',
padding: 10,
borderRadius: 10,
},
});

Resources