我想实现让相机预览占据整个屏幕的齐平外观,就像 Snapchat 对他们的应用程序所做的那样。问题是在预览接管屏幕时保持屏幕比例不变。有没有办法在本机反应中做到这一点?我的代码波纹管在底部生成一个带有黑条的预览,我必须保留它以便为相机预览提供正确的纵横比。 我假设我必须将预览的宽度负移出框架才能实现这一点,但我没有尝试过,我不确定这是否是正确的方法?
const { height, width } = Dimensions.get('window')
const CameraScreen = ({ navigation, route }) => {
let checkMarkSet = null
if (route.params) {
checkMarkSet = true
}
// RATIO SETTER
const [imagePadding, setImagePadding] = useState(0)
const [ratio, setRatio] = useState('4:3') // default is 4:3
const screenRatio = height / width
const [isRatioSet, setIsRatioSet] = useState(false)
async function prepareRatio() {
let desiredRatio = '4:3' // Start with the system default
// This issue only affects Android
if (Platform.OS === 'android') {
const ratios = await cameraRef.current.getSupportedRatiosAsync()
let distances = {}
let realRatios = {}
let minDistance = null
for (const ratio of ratios) {
const parts = ratio.split(':')
const ratioHeight = parseInt(parts[0])
const ratioWidth = parseInt(parts[1])
const realRatio = ratioHeight / ratioWidth
realRatios[ratio] = realRatio
// ratio can't be taller than screen, so we don't want an abs()
const distance = screenRatio - realRatio
distances[ratio] = realRatio
if (minDistance == null) {
minDistance = ratio
} else {
if (distance >= 0 && distance < distances[minDistance]) {
minDistance = ratio
}
}
}
// set the best match
desiredRatio = minDistance
// calculate the difference between the camera width and the screen height
const remainder = Math.floor(
(height - realRatios[desiredRatio] * width) / 2
)
// set the preview padding and preview ratio
setImagePadding(remainder / 2)
console.log(`okay look ${remainder / 2}`)
setRatio(desiredRatio)
// Set a flag so we don't do this
// calculation each time the screen refreshes
setIsRatioSet(true)
}
}
const setCameraReady = async () => {
if (!isRatioSet) {
await prepareRatio()
}
}
// RATIO SETTER
const [type, setType] = useState(Camera.Constants.Type.back)
const [activateCamera, setActivateCamera] = useState(false)
const [video, setVideo] = useState('')
const [showVideoModal, setShowVideoModal] = useState(false)
const insets = useSafeAreaInsets()
useFocusEffect(() => {
if (navigation.isFocused()) {
setActivateCamera(true)
}
})
const [pic, setPic] = useState(null)
const [showModal, setShowModal] = useState(false)
const cameraRef = useRef()
return (
<View
style={{
...styles.container,
// paddingTop: Platform.OS === 'android' ? insets.top : null,
}}
>
<StatusBar
style=""
translucent
backgroundColor="rgba(255,255,255,0)"
/>
<PinchGestureHandler onGestureEvent={onPinchGesture}>
<Reanimated.View
style={{
flex: 1,
backgroundColor: 'black',
justifyContent: 'flex-start',
paddingBottom: imagePadding * 4,
}}
>
{activateCamera && (
<Camera
style={{
// marginTop: imagePadding,
// marginBottom: imagePadding,
flex: 1,
// height: 733,
}}
ref={cameraRef}
type={type}
flashMode={flashMode}
zoom={zooming}
onCameraReady={setCameraReady}
ratio={ratio}
maxDuration={10000}
autoFocus="on"
>
<View
style={[
styles.contentContainer,
{
paddingTop: insets.top,
paddingBottom: insets.bottom,
top: insets.top,
bottom: insets.bottom,
},
]}
>
<View style={styles.topLeftCont}>
<TouchableOpacity
onPress={flipCameraHandler}
>
<Entypo
name="loop"
size={27}
color="white"
style={styles.flipIcon}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={flashSwitchHandler}
>
<Ionicons
name={
flashMode !== 'off'
? 'flash'
: 'flash-off'
}
size={27}
color="white"
style={styles.cameraSettingsButton}
/>
</TouchableOpacity>
</View>
<CameraButton
style={{
...styles.floatingPlusCont,
left: width / 2 - 45,
}}
onLongPress={beginRecording}
onEndPress={endRecording}
onTap={takePictureHandler}
/>
</View>
</Camera>
)}
</Reanimated.View>
</PinchGestureHandler>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
},
contentContainer: {
flex: 1,
position: 'absolute',
right: 0,
left: 0,
},
camera: {
flex: 1,
flexDirection: 'row',
},
topLeftCont: {
position: 'absolute',
width: 45,
top: 0,
right: 10,
borderRadius: 20,
backgroundColor: 'rgba(184,184,184,0.42)',
alignItems: 'center',
justifyContent: 'space-between',
// flexDirection: 'row',
padding: 5,
},
flipIcon: {
marginVertical: 7,
transform: [
{
rotate: '90deg',
},
],
},
cameraSettingsButton: { marginVertical: 7 },
modal: {
flex: 1,
position: 'absolute',
top: 0,
right: 0,
left: 0,
bottom: 0,
},
takenImage: { flex: 1 },
bottomCont: {
flex: 1,
justifyContent: 'flex-end',
padding: 10,
},
bottomButtonsCont: {
width: '100%',
justifyContent: 'space-between',
flexDirection: 'row',
paddingHorizontal: 5,
},
floatingPlusCont: {
bottom: 25,
position: 'absolute',
width: 90,
height: 90,
borderRadius: 45,
},
loadingView: {
backgroundColor: 'rgba(0,0,0,0.4)',
justifyContent: 'center',
alignItems: 'center',
},
})
export default CameraScreen