我是 React Native 和 Expo 的新手,我遵循了使用 Expo 的条形码扫描应用程序的在线教程,但它没有涵盖如何从 Expo 相机应用程序导航到另一个屏幕,我无法真正理解它出去。我让扫描仪正常工作,并使用 qrcode 数据创建了 django Rest 后端,但它仅应用文件名称,并且我希望导航到一个页面,该页面还包含我的 django 模型中列出的名称和描述。我确信我可能必须以某种方式更新我的 django 模型,但我确实可以在代码中使用一些帮助。这是我的 Django 模型:
from django.db import models
import qrcode
from io import BytesIO
from django.core.files.base import ContentFile
from PIL import Image
class Event(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
qr_code = models.ImageField(blank=True, upload_to='qrcodes/')
date = models.DateField()
def __str__(self):
return str(self.name)
def save(self, *args, **kwargs):
if not self.qr_code:
qrcode_img = qrcode.make(self.name)
canvas = Image.new('RGB', (qrcode_img.pixel_size, qrcode_img.pixel_size), 'white')
canvas.paste(qrcode_img)
fname = f'{self.name}.png'
buffer = BytesIO()
canvas.save(buffer, 'PNG')
self.qr_code.save(fname, ContentFile(buffer.getvalue()), save=False)
super().save(*args, **kwargs)
这是我的条码扫描仪屏幕的反应:
import React, { useState, useEffect } from "react";
import { Text, View, StyleSheet, Button } from "react-native";
import { CameraView, Camera } from "expo-camera";
import { useNavigation } from "@react-navigation/native";
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
const getCameraPermissions = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
};
getCameraPermissions();
}, []);
const navigation = useNavigation()
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
// alert(`Bar code with type ${type} and data ${data} has been scanned!`);
if (data) {
navigation.navigate('Event', {eventId: data} )
}
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
<CameraView
onBarcodeScanned={scanned ? undefined : handleBarCodeScanned}
barcodeScannerSettings={{
barcodeTypes: ["qr", "pdf417"],
}}
style={StyleSheet.absoluteFillObject}
/>
{scanned && (
<Button title={"Tap to Scan Again"} onPress={() => setScanned(false)} />
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "center",
},
});
最后这是我想根据条形码导航到的事件屏幕
import { useNavigation, useRoute } from "@react-navigation/native";
import { useLayoutEffect } from "react";
import { View, Text, StyleSheet } from "react-native";
import { HeaderBackButton } from '@react-navigation/elements';
const EventDetailScreen = () => {
const route = useRoute()
const navigation = useNavigation()
const {eventId, name, description} = route.params
useLayoutEffect(()=> {
navigation.setOptions({
headerTitle: name,
headerLeft: () => (
<HeaderBackButton
tintColor="white"
onPress={()=> navigation.goBack()}
/>
)
}, [])
})
return (
<View style={ Styles.screen }>
<Text style={{fontSize: 20}} >This is the event detail screen for {eventId}</Text>
<Text style={{fontSize: 20}} >{name}</Text>
<Text style={{fontSize: 20}} >{description}</Text>
</View>
);
}
const Styles = StyleSheet.create({
screen: {
padding:20,
}
})
export default EventDetailScreen
任何帮助将不胜感激。先谢谢你了
首先,更新 Django 后端以提供 API 端点以通过事件 ID 获取事件详细信息。
# views.py
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
from .models import Event
def get_event(request, event_id):
event = get_object_or_404(Event, id=event_id)
data = {
"name": event.name,
"description": event.description,
"date": event.date
}
return JsonResponse(data)
# urls.py
from django.urls import path
from .views import get_event
urlpatterns = [
path('event/<int:event_id>/', get_event, name='get_event'),
]
确保您已在导航器中注册了
EventDetailScreen
。
// App.js
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import BarcodeScannerScreen from './BarcodeScannerScreen';
import EventDetailScreen from './EventDetailScreen';
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="BarcodeScanner" component={BarcodeScannerScreen} />
<Stack.Screen name="EventDetail" component={EventDetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
更新条形码扫描仪屏幕以导航至事件详细信息屏幕并传递事件 ID。
// BarcodeScannerScreen.js
import React, { useState, useEffect } from "react";
import { Text, View, StyleSheet, Button } from "react-native";
import { Camera } from "expo-camera";
import { useNavigation } from "@react-navigation/native";
export default function BarcodeScannerScreen() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
const getCameraPermissions = async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === "granted");
};
getCameraPermissions();
}, []);
const navigation = useNavigation();
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
if (data) {
navigation.navigate('EventDetail', { eventId: data });
}
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
<Camera
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
{scanned && (
<Button title={"Tap to Scan Again"} onPress={() => setScanned(false)} />
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "center",
},
});
更新事件详细信息屏幕,以便在导航到后端时从后端获取事件详细信息。
// EventDetailScreen.js
import { useNavigation, useRoute } from "@react-navigation/native";
import React, { useEffect, useState } from "react";
import { View, Text, StyleSheet } from "react-native";
const EventDetailScreen = () => {
const route = useRoute();
const navigation = useNavigation();
const { eventId } = route.params;
const [event, setEvent] = useState(null);
useEffect(() => {
const fetchEventDetails = async () => {
try {
const response = await fetch(`http://your-django-backend-url/event/${eventId}/`);
const data = await response.json();
setEvent(data);
navigation.setOptions({ headerTitle: data.name });
} catch (error) {
console.error(error);
}
};
fetchEventDetails();
}, [eventId]);
if (!event) {
return <Text>Loading...</Text>;
}
return (
<View style={styles.screen}>
<Text style={{ fontSize: 20 }}>{event.name}</Text>
<Text style={{ fontSize: 20 }}>{event.description}</Text>
<Text style={{ fontSize: 20 }}>{event.date}</Text>
</View>
);
};
const styles = StyleSheet.create({
screen: {
padding: 20,
},
});
export default EventDetailScreen;
EventDetailScreen
。