You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,
  },
});

解决步骤及修改后的代码

关键修改点:

  1. 移除照片文本输入框:直接删除原照片文本输入组件,不再需要文本输入图片地址。
  2. 修复艺术家输入状态绑定:新增artist状态,修正原输入框错误更新歌曲状态的问题。
  3. 用组件内状态替代全局变量:减少全局变量使用,避免状态污染,用状态管理歌曲名、艺术家和图片URI。
  4. 传递正确的图片URI到Post实例:点击发布按钮时,将imageUri状态值传入Post构造函数,确保卡片获取有效图片地址。
  5. 修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:17:01