如何在 Swiftui 上将类型 'ImagePickerView' 的值转换为预期的参数类型 'String'?

How to convert value of type 'ImagePickerView' to expected argument type 'String' on Swiftui?

我正在尝试构建一个应用程序,用户可以在其中插入电影的名称,并可以将照片库中的图像直接添加到应用程序中(使用 UIKit。谢天谢地,用户可以在其中插入文本和照片库中的图像有效。我的问题是将该数据从 .sheet 传输到列表。用户插入的 TextFields 中的信息工作正常并显示在列表中,但图像不显示. 我一直收到错误“无法将类型 'ImagePickerView' 的值转换为预期的参数类型 'String'”。我不知道如何解决这个问题。这个问题出现在 ContentView.swift 文件中,当我尝试插入 Image() 时在 MovieRow 结构中。任何帮助将不胜感激。提前致谢。 下面是我的 ContentView 文件。 d

//  ContentView.swift
//  MovieListEditttt
//

import SwiftUI

struct ContentView: View {

@State var movieAdd: [MovieAdd] = []

@State private var newMovieName: String = ""
@State private var showNewMovie = false

@State private var newMovieImage = UIImage()

var body: some View {
    ZStack {
        VStack {
            HStack {
                Text("Movies Watched Ratings")
                    .font(.system(size: 40, weight: .black, design: .rounded
                    ))
                
                Spacer()
                
                Button(action: {
                    self.showNewMovie = true
                }) {
                    Image(systemName: "plus.circle.fill")
                        .font(.largeTitle)
                        .foregroundColor(.yellow)
                }
            }
            
            List{
                ForEach(movieAdd) {movie in
                    movieRow(movieAdd: movie)
                }
            }
        }
        
        if showNewMovie {
            BlankView(bGColor: .black)
                .opacity(0.5)
                .onTapGesture {
                    self.showNewMovie = false
                }
            NewMovieView(isShow: $showNewMovie, addMovie: $movieAdd, newMovieName: newMovieName)
                .transition(.move(edge: .bottom))
                .animation(.interpolatingSpring(stiffness: 200.0, damping: 25.0, initialVelocity: 10.0))
        }
    }
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}

struct movieRow: View {

@ObservedObject var movieAdd : MovieAdd

var body: some View {
        VStack {
            
            Image(movieAdd.movieImage)
                .resizable()
                .frame(width: 100, height: 100)
            
            Text(movieAdd.movieName)
        }
}
}

struct BlankView: View {
var bGColor: Color

var body: some View {
    VStack {
        Spacer()
    }
    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    .background(bGColor)
    .edgesIgnoringSafeArea(.all)
}
}

这是我的 MovieAdd.swift 文件,我在其中初始化将放入列表中的所有变量。

import Foundation

class MovieAdd: ObservableObject, Identifiable {
var id = UUID()
@Published var movieName = ""
@Published var isComplete : Bool = false
@Published var movieImage : ImagePickerView

init(movieName: String, isComplete: Bool = false, movieImage: ImagePickerView) {
    self.movieName = movieName
    self.isComplete = isComplete
    self.movieImage = movieImage
}
}

这是我的 NewMovieView.swift 文件,用户可以在其中将他们的电影信息插入到文本字段中,并从他们的照片库中插入图像。这里也是我使用 UIKit 的地方。

import SwiftUI

struct NewMovieView: View {

@Binding var isShow: Bool
@Binding var addMovie: [MovieAdd]

@State var newMovieName: String = ""

@State var isShowingImagePicker = false
@State var imageInBlackBox = UIImage()

var body: some View {
    ScrollView {
    VStack {
        VStack (alignment: .leading) {
            HStack {
                Text("Add a New Movie")
                    .font(.system(.title, design: .rounded))
                    .bold()
            }
            ZStack {
                VStack {
                HStack (alignment: .center){
                    
                    Spacer()
                    Image(uiImage: imageInBlackBox)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200, height: 200)
                        .border(Color.black, width: 3)
                        .clipped()
                    Spacer()
                }
                
                VStack {
                    Spacer()
                    Button(action: {
                        self.isShowingImagePicker.toggle()
                    }, label: {
                        Text("Select Image")
                            .font(.system(size: 15))
                    })
                    .sheet(isPresented: $isShowingImagePicker, content: { ImagePickerView(isPresented: $isShowingImagePicker, selectedImage: $imageInBlackBox)})
                }
                }
            }
            
            Group {
            TextField("Enter the movie name", text: $newMovieName)
            .padding()
            .background(Color(.systemGray6))
            
            }
            
            Button(action: {
                if self.newMovieName.trimmingCharacters(in: .whitespaces) == "" {
                    return
                }
                
                if self.isShowingImagePicker {
                    return 
                }
                
                self.isShow = false
                self.addMovieTask(movieName: self.newMovieName, movieImage: ImagePickerView(isPresented: $isShowingImagePicker, selectedImage: $imageInBlackBox))
            }) {
                Text("Save")
                    .font(.system(.headline, design: .rounded))
                    .foregroundColor(.red)
            }
        }
    }
        .background(Color.white)
    }
}

private func addMovieTask(movieName: String, isComplete: Bool = false, movieImage: ImagePickerView) {
    
    let task = MovieAdd(movieName: movieName, movieImage: movieImage)
    addMovie.append(task)
}
}

struct NewMovieView_Previews: PreviewProvider {
static var previews: some View {
    NewMovieView(isShow: .constant(true), addMovie: .constant([]), newMovieName: "", isShowingImagePicker: true)
}
}

struct ImagePickerView: UIViewControllerRepresentable {

@Binding var isPresented: Bool
@Binding var selectedImage: UIImage

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerView>) -> some UIViewController {
    let controller = UIImagePickerController()
    controller.delegate = context.coordinator
    return controller
}

func makeCoordinator() -> ImagePickerView.Coordinator {
    return Coordinator(parent: self)
}

class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    let parent: ImagePickerView
    init(parent: ImagePickerView){
        self.parent = parent
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let selectedImage = info[.originalImage] as? UIImage {
            print(selectedImage)
            self.parent.selectedImage = selectedImage
        }
        self.parent.isPresented = false
    }
}

func updateUIViewController(_ uiViewController: ImagePickerView.UIViewControllerType, context: UIViewControllerRepresentableContext<ImagePickerView>) {
    //
}
}

更改 #1:

您的模型应该通常struct 除非有真正令人信服的理由使其成为 ObservableObject。在这种情况下,struct 效果很好:

struct MovieAdd: Identifiable {
    var id = UUID()
    var movieName = ""
    var isComplete : Bool = false
    var movieImage : UIImage
}

请注意,我已将 movieImage 设为 UIImage

更改#2:

MovieRow中使用Image(uiImage:)MovieAdd 属性 不再需要 @ObservableObject 因为它只是一个 struct.

另请注意,Swift 中的类型应大写以遵循约定)。

struct MovieRow: View {
    
    var movieAdd : MovieAdd
    
    var body: some View {
        VStack {
            
            Image(uiImage: movieAdd.movieImage)
                .resizable()
                .frame(width: 100, height: 100)
            
            Text(movieAdd.movieName)
        }
    }
}

完整的代码,以防我忘记提及任何其他更改:


struct ContentView: View {
    
    @State var movieAdd: [MovieAdd] = []
    
    @State private var newMovieName: String = ""
    @State private var showNewMovie = false
    
    @State private var newMovieImage = UIImage()
    
    var body: some View {
        ZStack {
            VStack {
                HStack {
                    Text("Movies Watched Ratings")
                        .font(.system(size: 40, weight: .black, design: .rounded
                        ))
                    
                    Spacer()
                    
                    Button(action: {
                        self.showNewMovie = true
                    }) {
                        Image(systemName: "plus.circle.fill")
                            .font(.largeTitle)
                            .foregroundColor(.yellow)
                    }
                }
                
                List{
                    ForEach(movieAdd) {movie in
                        MovieRow(movieAdd: movie)
                    }
                }
            }
            
            if showNewMovie {
                BlankView(bGColor: .black)
                    .opacity(0.5)
                    .onTapGesture {
                        self.showNewMovie = false
                    }
                NewMovieView(isShow: $showNewMovie, addMovie: $movieAdd, newMovieName: newMovieName)
                    .transition(.move(edge: .bottom))
                    .animation(.interpolatingSpring(stiffness: 200.0, damping: 25.0, initialVelocity: 10.0))
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct MovieRow: View {
    
    var movieAdd : MovieAdd
    
    var body: some View {
        VStack {
            
            Image(uiImage: movieAdd.movieImage)
                .resizable()
                .frame(width: 100, height: 100)
            
            Text(movieAdd.movieName)
        }
    }
}

struct BlankView: View {
    var bGColor: Color
    
    var body: some View {
        VStack {
            Spacer()
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
        .background(bGColor)
        .edgesIgnoringSafeArea(.all)
    }
}

struct MovieAdd: Identifiable {
    var id = UUID()
    var movieName = ""
    var isComplete : Bool = false
    var movieImage : UIImage
}


struct NewMovieView: View {
    
    @Binding var isShow: Bool
    @Binding var addMovie: [MovieAdd]
    
    @State var newMovieName: String = ""
    
    @State var isShowingImagePicker = false
    @State var imageInBlackBox = UIImage()
    
    var body: some View {
        ScrollView {
            VStack {
                VStack (alignment: .leading) {
                    HStack {
                        Text("Add a New Movie")
                            .font(.system(.title, design: .rounded))
                            .bold()
                    }
                    ZStack {
                        VStack {
                            HStack (alignment: .center){
                                
                                Spacer()
                                Image(uiImage: imageInBlackBox)
                                    .resizable()
                                    .scaledToFill()
                                    .frame(width: 200, height: 200)
                                    .border(Color.black, width: 3)
                                    .clipped()
                                Spacer()
                            }
                            
                            VStack {
                                Spacer()
                                Button(action: {
                                    self.isShowingImagePicker.toggle()
                                }, label: {
                                    Text("Select Image")
                                        .font(.system(size: 15))
                                })
                                .sheet(isPresented: $isShowingImagePicker, content: { ImagePickerView(isPresented: $isShowingImagePicker, selectedImage: $imageInBlackBox)})
                            }
                        }
                    }
                    
                    Group {
                        TextField("Enter the movie name", text: $newMovieName)
                            .padding()
                            .background(Color(.systemGray6))
                        
                    }
                    
                    Button(action: {
                        if self.newMovieName.trimmingCharacters(in: .whitespaces) == "" {
                            return
                        }
                        
                        if self.isShowingImagePicker {
                            return
                        }
                        
                        self.isShow = false
                        self.addMovieTask(movieName: self.newMovieName, movieImage: ImagePickerView(isPresented: $isShowingImagePicker, selectedImage: $imageInBlackBox))
                    }) {
                        Text("Save")
                            .font(.system(.headline, design: .rounded))
                            .foregroundColor(.red)
                    }
                }
            }
            .background(Color.white)
        }
    }
    
    private func addMovieTask(movieName: String, isComplete: Bool = false, movieImage: ImagePickerView) {
        
        let task = MovieAdd(movieName: movieName, movieImage: movieImage.selectedImage)
        addMovie.append(task)
    }
}

struct NewMovieView_Previews: PreviewProvider {
    static var previews: some View {
        NewMovieView(isShow: .constant(true), addMovie: .constant([]), newMovieName: "", isShowingImagePicker: true)
    }
}

struct ImagePickerView: UIViewControllerRepresentable {
    
    @Binding var isPresented: Bool
    @Binding var selectedImage: UIImage
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerView>) -> some UIViewController {
        let controller = UIImagePickerController()
        controller.delegate = context.coordinator
        return controller
    }
    
    func makeCoordinator() -> ImagePickerView.Coordinator {
        return Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        let parent: ImagePickerView
        init(parent: ImagePickerView){
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let selectedImage = info[.originalImage] as? UIImage {
                print(selectedImage)
                self.parent.selectedImage = selectedImage
            }
            self.parent.isPresented = false
        }
    }
    
    func updateUIViewController(_ uiViewController: ImagePickerView.UIViewControllerType, context: UIViewControllerRepresentableContext<ImagePickerView>) {
        //
    }
}