The problem is, when I open camera the function inside onCameraReady isn't executed.
My Component:
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { type BarCodeScannedCallback, PermissionStatus } from 'expo-barcode-scanner';
import { Camera } from 'expo-camera';
import { useState, useCallback, useRef } from 'react';
import { View, StyleSheet, Platform, Pressable, Linking } from 'react-native';
import ScannerMarker from '@screens/CodeScanner/ScannerMarker';
import Button from '@components/Button';
import CustomText from '@components/CustomText';
import Layout from '@layouts/Layout';
import CloseIcon from '/assets/closeModal.svg';
import useCameraPermission from '@hooks/useCameraPermission';
import { globalStyles } from '@constants/styles';
import { moderateScale } from '@utils/dimensions';
import { barCodeScannerSettings, chooseBestRatio } from './helpers';
import { styles } from './styles';
const closeButtonSize = moderateScale(30);
const CodeScanner = () => {
const [cameraRatio, setCameraRatio] = useState('16:9');
const [scanned, setScanned] = useState(false);
const cameraRef = useRef<Camera>(null);
const { goBack } = useNavigation();
const { t } = useTypedTranslation();
const { status, canAskAgain, requestPermissions } = useCameraPermission();
const isCameraPermission = status === PermissionStatus.GRANTED;
const buttonText = canAskAgain ? "grant permission" : "open settings";
useFocusEffect(
useCallback(() => {
requestPermissions();
return () => setScanned(false);
}, [])
);
const handleBarCodeScanned: BarCodeScannedCallback = ({ data }) => {
setScanned(true);
goBack();
alert(`Bar code scanned! Received: ${data}`);
};
const onCameraReady = async () => {
if (Platform.OS === 'android') {
const cameraRatios = await cameraRef.current?.getSupportedRatiosAsync();
const chosenRatio = chooseBestRatio(cameraRatios);
setCameraRatio(prevState => chosenRatio ?? prevState);
}
};
if (!status) {
return null;
}
if (status === (PermissionStatus.DENIED || PermissionStatus.UNDETERMINED)) {
return (
<Layout>
<View style={styles.permissionDeniedContainer}>
<CustomText style={styles.permissionDeniedText} fontWeight="semi-bold">
No access to the camera
</CustomText>
<Button
onPress={canAskAgain ? requestPermissions : Linking.openSettings}
type="secondary"
containerStyle={styles.buttonContainer}
textStyle={styles.buttonText}
>
{buttonText}
</Button>
</View>
</Layout>
);
}
return (
<View style={styles.container}>
<Camera
ref={cameraRef}
barCodeScannerSettings={barCodeScannerSettings}
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={[StyleSheet.absoluteFill, styles.codeScanner]}
ratio={cameraRatio}
onCameraReady={onCameraReady}
>
{isCameraPermission && (
<>
<ScannerMarker />
<View style={styles.closeContainer}>
<Pressable style={styles.closeButton} onPress={goBack}>
<CloseIcon
width={closeButtonSize}
height={closeButtonSize}
color={globalStyles.colors.white}
/>
</Pressable>
</View>
</>
)}
</Camera>
</View>
);
};
export default CodeScanner;
The function executes when I closed the Camera components. The most interesting thing is when I add console.log() before if check inside onCameraReady function - it works and executes correct when Camera component is open
Modified function:
const onCameraReady = async () => {
console.log('trigger setting camera Ratio');
if (Platform.OS === 'android') {
const cameraRatios = await cameraRef.current?.getSupportedRatiosAsync();
const chosenRatio = chooseBestRatio(cameraRatios);
setCameraRatio(prevState => chosenRatio ?? prevState);
}
};
In the first case without console.log - the ratio isn't set correctly and the camera preview is distorted, and in second case the ratio is set correctly and preview looks good.
Is it possible to trigger function by execute console.log() ?
I have never met with problem like above. Maybe someone can help?
I want add this CodeScanner component to scan QR Codes, I have been tried expo-barcode-scanner, but it have problem with fit camera preview to all the screen, and I stay with expo-camera.
I need to detect supported ratios, and pick the best fit, becuase this app would be use by different customers with different devices
I don't have a solution to your problem per se. But I myself was working on android expo camera ratios and decided to mix your code with mine.
The following elementary code works just fine for me, onCameraReady is triggered at startup, as it should be. I hope this will help you :
By the way, the way you handle camera permission looks much cleaner than my method, would you mind sharing your @hooks/useCameraPermission ?