Can anyone help with integration of Clarifai Custom trained model in React Native? I found in docs that if you want to use custom instead of general model, you should pass object with model_id and model_version_id. As I created this custom model on their web page it gave me that parameters, but the algorithm won't really work and it returns the error of "request failed status code 400". Did anyone tried to implement this API in React Native?
const ScanMachine = props => {
const {id} = props.route.params;
const selectedCategory = CATEGORIES.find(cat => cat.id === id);
const camRef = useRef(null);
const [hasPermission, setHasPermission] = useState(null);
const [ratio, setRatio] = useState(null);
const [capturedPhoto, setCapturedPhoto] = useState(null);
const [prediction, setPrediction] = useState([]);
useEffect(() => {
(async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
setRatio('16:9');
})();
}, []);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
async function takePicture() {
if(camRef) {
let data = await camRef.current.takePictureAsync();
console.log(data);
setCapturedPhoto(data.uri);
return data.uri;
}
}
async function resize(photo) {
let imageManipulate = await ImageManipulator.manipulateAsync(photo, [{resize: {height: 350, width: 300}}], {base64: true});
return imageManipulate.base64;
}
async function predictions(image) {
let pred = await clarifai.models.predict({id: "custom_laundry_id", version: "03f4ff3ce1ba4cf68b77e923d0ce8699"}, image);
return pred;
}
async function detectObject() {
let photo = await takePicture();
let resized = await resize(photo);
let predict = await predictions(resized);
setPrediction(predict.outputs[0].data.concepts)
console.log(predict);
}
return (
<View style={{ flex: 1}}>
<Camera style={{ flex: 1, alignItems:'center'}} ref={camRef} ratio={ratio}>
<View style={{ flex: 1, backgroundColor: 'transparent', margin: 20, justifyContent: 'space-between'}}>
{prediction && <FlatList data={prediction.map(predict => ({
key: predict.name,
}))} renderItem={({ item }) => (
<Text style={{fontSize: 17, color: '#fff'}}>{item.key + " "}</Text>
)} numColumns={4} /> }
</View>
<BarcodeMask edgeColor={'#62B1F6'} backgroundColor={'transparent'} width={300} height={350} showAnimatedLine={false} />
<View style={{flex: 1, justifyContent: 'space-between', justifyContent:'flex-end', margin: 20}}>
<TouchableOpacity style={{ backgroundColor: 'transparent', alignSelf: 'flex-end'}} onPress={detectObject}>
<FontAwesome name="camera" style={{color: '#fff', fontSize: 40, alignContent: 'flex-start'}} />
</TouchableOpacity>
</View>
</Camera>
{/* { capturedPhoto &&
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center', margin: 20}}>
<Image style={{width: '100%', height: '100%', borderRadius: 10}} source={{uri: capturedPhoto}} />
</View> } */}
</View>
);
};
Related
The filter buttons on my React Native work in terms of filtering the data, but it doesn't keep the data that was filtered out, so I can only filter the data once and would have to input them again. I would like it to be able to filter without losing the data, so I can continuously switch between the different filters and show that they all work without needing to add new data.
import React, { useState } from 'react';
import {StyleSheet,Text,View,TextInput,TouchableOpacity,FlatList,Alert,Modal, Dimensions} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
function App() {
const [todoInput, settodoInput] = React.useState('')
const [Todos, setTodos] = React.useState([]);
const [FilterTodos, setFilterTodos] = React.useState([Todos]);
const StatusTab = [
{
status: 'All',
completed: 'All'
},
{
status: 'Complete',
completed: true
},
{
status: 'Incomplete',
completed: false
}
]
const [Status,setStatus] = useState('All');
const setStatusFilter = Status => {
if(Status !== 'All') {
setTodos([...Todos.filter(e => e.completed === Status)])
} else {
setTodos(Todos)
}
setStatus(Status);
};
const [isRender,setisRender] = useState(false);
const [modalVisible, setmodalVisible] = useState(false);
const [editText, seteditText] = useState();
const [editItem, seteditItem] = useState();
React.useEffect(()=>{
GetTasks();
},[]);
React.useEffect(()=>{
SaveTasks(Todos);
},[Todos]);
const ListItem = ({Todo}) => {
return <View style={styles.ListItem}>
<View style={{flex:1}}>
<Text style={[styles.TaskText,{textDecorationLine: Todo?.completed?"line-through":"none"}]}>{Todo?.task}</Text>
</View>
{!Todo?.completed && (
<TouchableOpacity style={[styles.EditIcon]} onPress={()=>completeTodo(Todo?.id)}>
<Icon name='done' size={20} color='#FFFFFF'/>
</TouchableOpacity>
)}
<TouchableOpacity style={[styles.EditIcon,{backgroundColor:'#5D76E8'}]}
onPress={()=>editTodo(Todo?.id)}>
<Icon name='edit' size={20} color='#FFFFFF'/>
</TouchableOpacity>
<TouchableOpacity style={[styles.EditIcon,{backgroundColor:'#D30404'}]}
onPress={()=>deleteTodo(Todo?.id)}>
<Icon name='delete' size={20} color='#FFFFFF'/>
</TouchableOpacity>
</View>
}
const SaveTasks = async Todos =>{
try {
const stringifyTodos = JSON.stringify(Todos)
await AsyncStorage.setItem('Todos', stringifyTodos)
} catch (e) {
console.log(e);
// saving error
}
};
const GetTasks = async () => {
try {
const Todos = await AsyncStorage.getItem('Todos');
if(Todos != null){
setTodos(JSON.parse(Todos));
}
} catch (error) {
console.log(error);
}
};
const addTodo = () =>{
if(todoInput == ""){
Alert.alert("Error","Please Input Task");
}
else{
// console.log(todoInput);
const newTodo = {
id:Math.random(),
task: todoInput,
completed: false,
};
setTodos([...Todos,newTodo])
settodoInput('');
}
}
const completeTodo = (todoID) => {
console.log(todoID);
const newTodos = Todos.map((item)=>{
if(item.id == todoID){
return {...item,completed:true}
}
return item;
});
setTodos(newTodos);
};
const editTodo = (item) => {
setmodalVisible(true);
seteditText(item.text);
seteditItem(item.id);
};
const handleEditItem = (editItem) =>{
const newData =Todos.map(item =>{
if (item.id == editItem) {
item.text = editText;
return item
}
return item;
})
setTodos(newData);
setisRender(!isRender);
}
const onPressSaveEdit = () => {
handleEditItem(editItem);
setmodalVisible(false);
}
const deleteTodo = (todoID) =>{
Alert.alert("Confirm","Delete Task?",[{
text:"Yes",
onPress: () => {const newTodos = Todos.filter(item => item.id != todoID);
setTodos(newTodos)}
},
{text:"No"}
])
};
return (
<View style={styles.Container}>
<View style={styles.Header}>
<TextInput style={styles.SearchBar} placeholder='Add Task'
value={todoInput} onChangeText={(text)=>settodoInput(text)}/>
<TouchableOpacity onPress={addTodo}>
<View style={styles.IconContainer}>
<Icon name="add" color='#FFFFFF' size={30}/>
</View>
</TouchableOpacity>
</View>
<View style={styles.TaskList}>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{padding:20,paddingBottom:100}}
data={Todos}
keyExtractor={(item) => item.id.toString()}
renderItem={({item})=><ListItem Todo={item}/>}
extraData={isRender}/>
<Modal
animationType='fade'
visible={modalVisible}
onRequestClose={() => setmodalVisible(false)}
>
<View style={styles.ModalView}>
<Text style={styles.ModalText}>Change Task:</Text>
<TextInput style={styles.ModalInput}
onChangeText={(text) => seteditText(text)}
defaultValue={editText}
editable={true}
multiline={false}
maxLength={200}/>
<Text style={styles.ModalText}>Task Status:</Text>
<TouchableOpacity style={styles.FilterTab}>
<Text style={styles.TabText}>Complete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.FilterTab}>
<Text style={styles.TabText}>Incomplete</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={()=> onPressSaveEdit()}
style={styles.SaveButton}>
<Text style={styles.ModalText}>Save</Text>
</TouchableOpacity>
</View>
</Modal>
</View>
<View style={styles.Footer}>
{
StatusTab.map(e => (
<TouchableOpacity style={[styles.FilterTab, Status === e.completed && styles.FilterTabActive]}
onPress={() => setStatusFilter(e.completed)}>
<Text style={[styles.TabText, Status === e.status && styles.TabTextActive]}>{e.status}</Text>
</TouchableOpacity>
))
}
</View>
</View>
);
}
const styles = StyleSheet.create({
Container:{
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
Header:{
flexDirection: 'row',
backgroundColor:'#000000',
alignItems: "center",
justifyContent: 'center',
width:'100%'
},
SearchBar:{
borderColor: "#FFFFFF",
backgroundColor: "#DDDDDD",
marginHorizontal: 5,
width: '40%',
height:'80%',
borderRadius: 30
},
IconContainer:{
height: 50,
width: 50,
backgroundColor: '#061380',
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center'
},
TaskList:{
flex: 10,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-around',
alignItems: 'center'
},
ListItem:{
padding:20,
backgroundColor:'#DEDEDE',
flexDirection:'row',
elevation:12,
borderRadius:7,
marginVertical:10
},
TaskText:{
fontWeight:'bold',
fontSize:15,
color:'#000000',
},
EditIcon:{
height:25,
width:25,
backgroundColor:'#1BCC48',
justifyContent:'center',
alignItems:'center',
marginLeft:5,
borderRadius:3
},
ModalView:{
flex:1,
alignItems:'center',
justifyContent:'center'
},
ModalText:{
fontSize:25,
fontWeight:'bold',
marginVertical:30,
marginLeft:10
},
ModalInput:{
width:'90%',
height:70,
borderColor:'#000000',
borderWidth:1,
fontSize:25
},
SaveButton:{
backgroundColor:'#3AE3A0',
paddingHorizontal:100,
alignItems:'center',
marginTop:20
},
Footer:{
flexDirection:'row',
alignSelf:'center',
marginBottom:10
},
FilterTab:{
width:Dimensions.get('window').width / 3.5,
flexDirection:'row',
borderWidth:1,
borderColor:'#4A4A4A',
padding:10,
justifyContent:'center'
},
FilterTabActive:{
backgroundColor:'#F87861'
},
TabText:{
fontSize:16,
},
TabTextActive:{
color:'#FFFFFF'
},
});
export default App;
added a new method and passing it to the Flatlist
const getTodos = (status) => {
return status === 'All'
? Todos
: Todos.filter((item) => item.completed === status);
};
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{ padding: 20, paddingBottom: 100 }}
data={getTodos(Status)}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <ListItem Todo={item} />}
extraData={isRender}
/>
please check this
demo code
I think you are changing the data array when filtering with:
setTodos([...Todos.filter(e => e.completed === Status)])
How I did it (similar) in my app:
const [filtered, setFiltered] = useState(setStatusFilter());
then you should
setFiltered([...Todos.filter(e => e.completed === Status)])
to have the filtered values in const filtered and the source list stay the same as before.. and you can then use the filtered to show in a mapping ..
I am tasked with the problem of creating a react-native using expo-opencv, expo-camera, Canny, Contour detection library or SIFT to get distance between the shoulders, the length of the inseam, chest circumference, waist circumference, length of the arms , length of the legs , arm/wrist circumference and leg circumference
I need some help which libraries to use and how to integrate all of them. this is what is have tried:
import React, { useState } from 'react';
import { Text, View, TouchableOpacity, Image } from 'react-native';
import { Camera } from 'expo-camera';
import * as cv from 'expo-opencv';
const BodyMeasurement = () => {
const [hasPermission, setHasPermission] = useState(null);
const [image, setImage] = useState(null);
useEffect(() => {
(async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
const takePicture = async () => {
const photo = await camera.takePictureAsync();
setImage(photo.uri);
processImage(photo.uri);
};
const processImage = async (imageUri) => {
const mat = cv.imread(imageUri);
// perform image processing using OpenCV functions
// for example, converting the image to grayscale
const grayMat = cv.cvtColor(mat, cv.COLOR_RGBA2GRAY);
// Extract measurement using OpenCV functions
//
// ...
};
return (
<View>
{image ? (
<Image source={{ uri: image }} style={{ width: '100%', height: 300 }} />
) : (
<Camera
style={{ flex: 1 }}
type={Camera.Constants.Type.back}
ref={ref => {
this.camera = ref;
}}>
<View style={{ flex: 1, backgroundColor: 'transparent', alignItems: 'center' }}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
takePicture();
}}>
<Text style={{ fontSize: 18, marginBottom: 10, color: 'white' }}>
{' '}Take Picture{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
)}
</View>
);
};
export default BodyMeasurement;
this may sound stupid for the most of you but I'm new when it comes to using API and react native. My situation is the next. From my data I try to display questions and a text field so the customer can answer and therefore I retrieve the data. But my problem is the next on when I display and try to write in the TextInput no matter how I have they will all copy what I write in which ever one I'm writing on. I don't get what I am doing wrong. I tried with looping but I can't seem to get the right answer to solve my problem. Here's my code if someone can help me.
//import liraries
import React, { Component, useEffect, useState } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TextInput,
Picker,
} from 'react-native';
// create a component
const Get = ({ navigation }) => {
const [user, setUser] = useState();
// const [text, onChangeText] = React.useState(null);
const [selectedValue, setSelectedValue] = useState("Test");
const [text, onChangeText] = useState('');
const getUserData = async () => {
try {
let response = await fetch('https://survey-back-nmucl6ui6q-ey.a.run.app/survey/7b504f09-7a67-4f99-a402-c15a9388446c', {
headers: new Headers({
'Authorization': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTUxNTU1MjMsImlhdCI6MTY1NTA2OTExOCwic3ViIjoxfQ.eoLaDT4wP99yjC38DN2Zck2sgwXFvcRYrfzxszHkQvc',
'Content-Type': 'application/x-www-form-urlencoded'
}),
});
let json = await response.json();
console.log(json.question)
setUser(json.question);
} catch (error) {
console.error(error);
}
};
useState(() => {
getUserData();
}, []);
const renderItem = ({ item }) => {
return (
<View
style={{
borderBottomWidth: 1,
borderBottomColor: '#ccc',
padding: 5,
}}>
{item.question_type == 'text-field' ?
<View style={styles.questions}>
<Text style={styles.label}>{item.name}</Text>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
placeholder="Entrez votre réponse"
/>
</View>
: <Text>Erreur</Text>}
{item.question_type == 'select' ?
<View style={styles.questions}>
<Text style={styles.label}>{item.name}</Text>
<Picker
selectedValue={selectedValue}
onValueChange={(itemValue, itemIndex) =>
setSelectedValue(itemValue)}
>
{Object.keys(item.choice).map(key =>{
return (
<Picker.Item label={key} value={key} key={key} />
)
})}
</Picker>
</View>
: <Text style={{display: 'none'}}>Erreur</Text>}
<View>
{item.question_type == 'comboboxMulti' ?
<Text style={{ fontWeight: 'bold' }}>{item.name}</Text>
: <Text style={{display: 'none'}}>Ça marche pas</Text>}
</View>
</View>
);
};
return (
<View style={styles.container}>
<FlatList
data={user}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
// define your styles
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
borderRadius: 5,
marginLeft: 0,
},
label: {
textTransform: 'capitalize',
},
questions: {
justifyContent: 'center',
alignItems: 'start',
}
});
//make this component available to the app
export default Get;
I'm new to react native and I'm having some performance problem with flatlist in React Native Expo. On my screen I'm displaying a list of contacts and I want them to be selected or deselected and I have managed to achieve that part but the problem is that it takes a lot of visibility time to check the contacts or to uncheck them. Making the screen not very user friendly. I have tried a lot of solutions that I've found on internet regarding this problem but none of them had worked. Hope someone can help me. Below I'll attach the code!
function ContactList() {
const [itemChecked, setItemChecked] = useState([]);
const [checked, setChecked] = useState(false);
const [contacts, setContacts] = useState([]);
const [filter, setFilter] = useState([]);
const [search, setSearch] = useState('');
const [checkedBox, setCheckedBox] = useState(false);
useEffect(() => {
(async () => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === 'granted') {
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.PhoneNumbers],
// fields: [Contacts.Fields.Name],
});
if (data.length > 0) {
setContacts(data);
setFilter(data);
// console.log('contact', contacts[1]);
// console.log('filter', filter);
}
}
})();
}, []);
const searchFilter = (text) => {
if (text) {
const newData = contacts.filter((item) => {
const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilter(newData);
setSearch(text);
} else {
setFilter(contacts);
setSearch(text);
}
};
const onChangeValue = (item, index) => {
if (itemChecked.includes(item.phoneNumbers[0].digits)) {
itemChecked.splice(itemChecked.indexOf(item.phoneNumbers[0].digits), 1);
} else {
itemChecked.push(item.phoneNumbers[0].digits);
setCheckedBox(true);
}
setItemChecked(itemChecked);
console.log(itemChecked);
// console.log(item);
};
const renderItem = ({ item, index }) => {
return (
<SafeAreaView>
<ScrollView>
<TouchableOpacity style={{ flexDirection: 'row', flex: 1 }}>
<View style={{ flex: 1, borderTopWidth: 0.5, borderTopColor: 'grey', marginBottom: 15 }}>
<Text onPress={() => setChecked(true)} style={{ fontSize: 20, marginHorizontal: 10 }}>
{item.name + ' '}
</Text>
<Text style={{ fontSize: 17, marginHorizontal: 10, marginTop: 5, color: 'grey' }}>
{item.phoneNumbers && item.phoneNumbers[0] && item.phoneNumbers[0].number}
</Text>
</View>
<View style={{ flex: 1, borderTopWidth: 0.5, borderTopColor: 'grey' }}>
{itemChecked.includes(item.phoneNumbers[0].digits) === false ? (
<CheckBox
style={{ width: 15, height: 15 }}
right={true}
checked={false}
onPress={() => {
onChangeValue(item, index);
}}
/>
) : (
<CheckBox
style={{ width: 15, height: 15, paddingTop: 8 }}
right={true}
checked={true}
onPress={() => {
onChangeValue(item, index);
}}
/>
)}
</View>
{/* <Post postJson={item} isGroupAdmin={isGroupAdmin} user={user} /> */}
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.container}>
<View
style={{
height: 40,
justifyContent: 'center',
backgroundColor: '#eeeeee',
width: '90%',
marginHorizontal: 20,
marginTop: 15,
borderRadius: 10,
}}
>
<Feather name="search" size={20} color="grey" style={{ position: 'absolute', left: 32 }} />
<TextInput
placeholder="Search"
placeholderTextColor="#949494"
style={{
left: 20,
paddingHorizontal: 35,
fontSize: 20,
}}
value={search}
onChangeText={(text) => {
searchFilter(text);
setSearch(text);
}}
/>
</View>
<FlatList
style={{ marginTop: 15 }}
data={contacts && filter}
keyExtractor={(item) => `key-${item.id.toString()}`}
renderItem={renderItem}
refreshing={true}
initialNumToRender={10}
ListEmptyComponent={<Text message="No contacts found." />}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
export default ContactList;
I have just started using React Native with Expo so I am kind of confused. So, I have made a camera component which I imported in the main screen. Everything looks good. But I can't take pictures. I cannot click the snap icon and save the image. Is there a component that I missed?
I have only posted the CameraComponent class below.
Camera.js
class CameraComponent extends 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, justifyContent: 'space-between' }}
type={this.state.type}
>
<Header
searchBar
rounded
style={{
position: 'absolute',
backgroundColor: 'transparent',
left: 0,
top: 0,
right: 0,
zIndex: 100,
alignItems: 'center'
}}
>
<View style={{ flexDirection: 'row', flex: 4 }}>
<Ionicons name="md-camera" style={{ color: 'white' }} />
<Item style={{ backgroundColor: 'transparent' }}>
<Icon name="ios-search" style={{ color: 'white', fontSize: 24, fontWeight: 'bold' }}></Icon>
</Item>
</View>
<View style={{ flexDirection: 'row', flex: 2, justifyContent: 'space-around' }}>
<Icon name="ios-flash" style={{ color: 'white', fontWeight: 'bold' }} />
<Icon
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back ?
Camera.Constants.Type.front :
Camera.Constants.Type.back
})
}}
name="ios-reverse-camera"
style={{ color: 'white', fontWeight: 'bold' }}
/>
</View>
</Header>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 30, marginBottom: 15, alignItems: 'flex-end' }}>
<Ionicons name="ios-map" style={{ color: 'white', fontSize: 36 }}></Ionicons>
<View></View>
<View style={{ alignItems: 'center' }}>
<MaterialCommunityIcons name="circle-outline" // This is the icon which should take and save image
style={{ color: 'white', fontSize: 100 }}
></MaterialCommunityIcons>
<Icon name="ios-images" style={{ color: 'white', fontSize: 36 }} />
</View>
</View>
</Camera>
</View>
)
}
}
}
export default CameraComponent;
The icon in the center i;e circle icon should automatically take and save image.
You can use "onPictureSaved" when the asynchronous takePictureAsync function returns so that you can grab the photo object:
takePicture = () => {
if (this.camera) {
this.camera.takePictureAsync({ onPictureSaved: this.onPictureSaved });
}
};
onPictureSaved = photo => {
console.log(photo);
}
In the view you would have a Camera component that has a ref:
<Camera style={styles.camera} type={this.state.type} ref={(ref) => { this.camera = ref }} >
As well as a button that will call the takePicture function on press:
<TouchableOpacity style={styles.captureButton} onPress={this.takePicture} />
So you need to tell your 'circle icon' to take the picture. First I would add a reference to your camera like so
<Camera style={{ flex: 1 }}
ref={ (ref) => {this.camera = ref} }
type={this.state.type}>
then create a function that actually tells your app to take the photo:
async snapPhoto() {
console.log('Button Pressed');
if (this.camera) {
console.log('Taking photo');
const options = { quality: 1, base64: true, fixOrientation: true,
exif: true};
await this.camera.takePictureAsync(options).then(photo => {
photo.exif.Orientation = 1;
console.log(photo);
});
}
}
Now make your icon have an onPress() to take the photo. I did something like this.
<TouchableOpacity style={styles.captureButton} onPress={this.snapPhoto.bind(this)}>
<Image style={{width: 100, height: 100}} source={require('../assets/capture.png')}
/>
</TouchableOpacity>
You may also want to create a view that renders an image preview or something similar. The Expo documentation has a fairly good example on getting started. Note that Expo creates a cached folder called 'Camera' and that's where the image initially is.
You can do this in a functional component as well using a ref created via a React Hook. Here is an example based on the expo SDK 38 Camera component https://docs.expo.io/versions/v38.0.0/sdk/camera/
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera } from 'expo-camera';
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const ref = useRef(null)
useEffect(() => {
(async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
_takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={type} ref={ref}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
setType(
type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
}}>
<Text style={{ fontSize: 18, marginBottom: 10, color: 'white' }}> Flip </Text>
</TouchableOpacity>
<TouchableOpacity
onPress={_takePhoto}
>
<Text>Snap Photo</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
I did not check what the UI for that looks like but the main point is to utilize React.useRef and attach the ref to your <Camera/> component. Then you may call ref.current.takePictureAsync to capture and access a new image. Look below to see the important relevant snippets for capturing a photo.
import React from 'react'
/* ... other imports
*/
export default CameraScene = () => {
/* ... other state and permission logic
*/
const ref = useRef(null)
const _takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
return (
<Camera style={{flex: 1}} ref={ref}> /* ...
... other ui logic
*/
</Camera>
)
}
Learn more about useRef here https://reactjs.org/docs/hooks-reference.html#useref)
You'll need to add a ref to the Camera class to be able to call it's takePictureAsync function within your own 'handle' method.
cameraRef = React.createRef();
<Camera ref={this.cameraRef}>...</Camera>
Don't forget ".current" when calling the method of the referenced camera.
handlePhoto = async () => {
if(this.cameraRef){
let photo = await this.cameraRef.current.takePictureAsync();
console.log(photo);
}
}
Then simply call your 'handle' method on a touchable element acting as the photo-snap button.
<TouchableOpacity
style={{width:60, height:60, borderRadius:30, backgroundColor:"#fff"}}
onPress={this.handlePhoto} />
You should be able to see the photo logged in your console.
Are you trying to do this on an actual physical device? You can't shoot pictures with an emulator.