如何在Expo Go中用上传图片替代文本输入并传至另一屏幕?
Expo Go项目:替换照片文本输入框为上传图片的解决方案
我的Expo Go项目当前逻辑是:用户输入歌曲名、艺术家名和照片文本,这些内容会生成卡片并传递到另一屏幕展示;同时已实现调用相册选择上传图片的功能。我希望将照片文本输入框替换为上传的图片,尝试将postPhoto赋值为uri等方式均出现报错,相关代码如下:
import { StatusBar } from 'expo-status-bar'; import { Platform, StyleSheet, TextInput, SafeAreaView, Pressable, TouchableOpacity, Image, Button } from 'react-native'; import { useState } from 'react'; import EditScreenInfo from '../components/EditScreenInfo'; import { Text, View } from '../components/Themed'; import { useNavigation } from '@react-navigation/native'; import { CompositeScreenProps } from '@react-navigation/native'; import { RootStackScreenProps } from '../types'; import { getCurrentUser} from '../components/makeAccount'; import * as ImagePicker from 'expo-image-picker'; let postSong:string let postArtist:string let postPhoto: string let userPost: JSX.Element let saved :boolean = false export function getSaved(){ return saved } export function getUserPost(){ return userPost } export default function PostScreen({ navigation }: RootStackScreenProps<'Post'>) { const [song, setSong] = useState('song'); const [image, setImage] = useState<string | null>(null); const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, aspect: [4, 3], quality: 1, }); console.log(result); if (!result.canceled) { setImage(result.assets[0].uri); } }; let test = new Post('postSong', "postArtist", "postPhoto") return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Enter a Song' placeholderTextColor="rgb(41, 41, 95 )" onChangeText={(val) => { setSong(val) postSong = val } }/> <TextInput style={styles.input} placeholder='Enter the Artist' placeholderTextColor="rgb(41, 41, 95 )" onChangeText={(val) => { setSong(val) // 此处错误:应该更新艺术家状态而非歌曲状态 postArtist = val } }/> <TextInput style={styles.input} placeholder='Enter a Photo' placeholderTextColor="rgb(41, 41, 95 )" onChangeText={(val) => { postPhoto = val } }/> <Button title="Pick an image to upload with your song" onPress={pickImage} /> {image && <> <Image source={{ uri: image }} style={{ width: 200, height: 200 }} /> </>} <Text style={styles.newText}> The song you will post is: {song}</Text> <TouchableOpacity style = {styles.button} onPress={() =>{ test = new Post(postSong, postArtist, postPhoto) saved = true userPost = test.card() navigation.replace('Root') }} > <Text style = {styles.buttonText}>Post Song</Text> </TouchableOpacity> </View> ) } class Post{ songName:string artist:string picture:string constructor(songName:string, artist: string, picture: string){ this.songName = songName this.artist = artist this.picture = picture } card(){ console.log("Song Name: ", this.songName) console.log("Song Artist: ", this.artist) console.log("Song Photo: ", this.picture) return( <View style = {styles.songBase}> <View style = {styles.songData}> <Text style = {styles.songPoster}> Posted by : {getCurrentUser()}</Text> <Text style = {styles.songInfo}>Song : {this.songName}</Text> <Text style = {styles.songInfo}>Artist: {this.artist}</Text> </View> <View style = {styles.songPhoto}> <Image source={{uri: this.picture}} style = {styles.songPhoto}/> {/* 样式冲突:容器和图片共用同一样式 */} </View> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgb(204, 197, 244)', }, input: { height: 40, width: "80%", alignSelf:"center", borderColor: 'rgb(41, 41, 95 )', borderWidth: 2, borderRadius: 10, marginVertical: 5, textAlign: 'center', color:"rgb(41, 41, 95 )", }, title: { fontSize: 20, fontWeight: 'bold', }, separator: { marginVertical: 30, height: 1, width: '80%', }, newText: { fontSize: 12, color:'black', }, songBase:{ width: '80%', height: 200, borderColor : "rgb(41, 41, 95 )", borderWidth: 10, borderRadius: 45, flexDirection: 'column', backgroundColor: "#111" }, songData:{ flex: 1, borderColor : 'white', borderRadius: 45, width: "95%", alignSelf: 'center', backgroundColor:"#111", }, songPhoto:{ flex:2, aspectRatio: 1, borderColor : 'rgb(204, 197, 244 )', borderWidth: 5, alignSelf: 'center', }, songInfo:{ fontWeight: 'bold', fontSize: 15, alignSelf: 'auto', color: 'rgb(204, 197, 244 )', }, songPoster:{ fontSize: 10, alignSelf: 'flex-end', color: 'rgb(204, 197, 244 )', marginRight: 20 }, button: { height: 40, width: 200, backgroundColor: "rgb(41, 41, 95 )", borderColor: "rgb(204, 197, 244 )", borderWidth: 2, borderRadius: 10, justifyContent: "center", alignItems: "center", margin: 5, alignSelf: "center" }, buttonText: { color: "rgb(204, 197, 244 )", fontWeight: "bold", margin: 5, }, });
解决步骤及修改后的代码
关键修改点:
- 移除照片文本输入框:直接删除原照片文本输入组件,不再需要文本输入图片地址。
- 修复艺术家输入状态绑定:新增
artist状态,修正原输入框错误更新歌曲状态的问题。 - 用组件内状态替代全局变量:减少全局变量使用,避免状态污染,用状态管理歌曲名、艺术家和图片URI。
- 传递正确的图片URI到Post实例:点击发布按钮时,将
imageUri状态值传入Post构造函数,确保卡片获取有效图片地址。 - 修复Image样式冲突:给卡片内的Image单独设置样式,避免和外层容器样式冲突导致的布局异常。
修改后的完整代码:
import { StatusBar } from 'expo-status-bar'; import { StyleSheet, TextInput, TouchableOpacity, Image, Button } from 'react-native'; import { useState } from 'react'; import { Text, View } from '../components/Themed'; import { RootStackScreenProps } from '../types'; import { getCurrentUser} from '../components/makeAccount'; import * as ImagePicker from 'expo-image-picker'; let userPost: JSX.Element let saved :boolean = false export function getSaved(){ return saved } export function getUserPost(){ return userPost } export default function PostScreen({ navigation }: RootStackScreenProps<'Post'>) { // 用组件内状态管理输入内容和图片 const [song, setSong] = useState(''); const [artist, setArtist] = useState(''); const [imageUri, setImageUri] = useState<string | null>(null); const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, aspect: [4, 3], quality: 1, }); if (!result.canceled) { setImageUri(result.assets[0].uri); } }; return ( <View style={styles.container}> {/* 歌曲名输入框 */} <TextInput style={styles.input} placeholder='Enter a Song' placeholderTextColor="rgb(41, 41, 95 )" onChangeText={setSong} value={song} /> {/* 艺术家输入框 */} <TextInput style={styles.input} placeholder='Enter the Artist' placeholderTextColor="rgb(41, 41, 95 )" onChangeText={setArtist} value={artist} /> {/* 图片选择按钮和预览 */} <Button title="Pick an image to upload with your song" onPress={pickImage} /> {imageUri && ( <Image source={{ uri: imageUri }} style={{ width: 200, height: 200, marginVertical: 10 }} /> )} <Text style={styles.newText}> The song you will post is: {song}</Text> <TouchableOpacity style={styles.button} onPress={() =>{ // 可选:添加未选择图片的提示逻辑 if (!imageUri) return; // 创建Post实例并传入当前状态值 const post = new Post(song, artist, imageUri); saved = true; userPost = post.card(); navigation.replace('Root'); }} > <Text style={styles.buttonText}>Post Song</Text> </TouchableOpacity> </View> ) } class Post{ songName:string artist:string picture:string constructor(songName:string, artist: string, picture: string){ this.songName = songName this.artist = artist this.picture = picture } card(){ return( <View style={styles.songBase}> <View style={styles.songData}> <Text style={styles.songPoster}> Posted by : {getCurrentUser()}</Text> <Text style={styles.songInfo}>Song : {this.songName}</Text> <Text style={styles.songInfo}>Artist: {this.artist}</Text> </View> <View style={styles.songPhotoContainer}> {/* 图片单独使用专属样式 */} <Image source={{uri: this.picture}} style={styles.songPhotoImage}/> </View> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgb(204, 197, 244)', }, input: { height: 40, width: "80%", alignSelf:"center", borderColor: 'rgb(41, 41, 95 )', borderWidth: 2, borderRadius: 10, marginVertical: 5, textAlign: 'center', color:"rgb(41, 41, 95 )", }, newText: { fontSize: 12, color:'black', marginVertical: 10, }, songBase:{ width: '80%', height: 200, borderColor : "rgb(41, 41, 95 )", borderWidth: 10, borderRadius: 45, flexDirection: 'column', backgroundColor: "#111" }, songData:{ flex: 1, borderColor : 'white', borderRadius: 45, width: "95%", alignSelf: 'center', backgroundColor:"#111", justifyContent: 'center', paddingHorizontal: 10, }, songPhotoContainer:{ flex:2, aspectRatio: 1, borderColor : 'rgb(204, 197, 244 )', borderWidth: 5, alignSelf: 'center', borderRadius: 35, overflow: 'hidden', }, songPhotoImage:{ width: '100%', height: '100%', }, songInfo:{ fontWeight: 'bold', fontSize: 15, color: 'rgb(204, 197, 244 )', marginVertical: 2, }, songPoster:{ fontSize: 10, alignSelf: 'flex-end', color: 'rgb(204, 197, 244 )', marginRight: 20, marginBottom: 5, }, button: { height: 40, width: 200, backgroundColor: "rgb(41, 41, 95 )", borderColor: "rgb(204, 197, 244 )", borderWidth: 2, borderRadius: 10, justifyContent: "center", alignItems: "center", margin: 5, alignSelf: "center" }, buttonText: { color: "rgb(204, 197, 244 )", fontWeight: "bold", margin: 5, }, });
内容的提问来源于stack exchange,提问作者Joe M
相关产品推荐
相关产品推荐

