问题描述
我正在尝试构建一个应用程序,用户可以在其中插入电影名称,并且可以直接从照片库中将图像添加到应用程序中(使用 UIKit。值得庆幸的是,用户可以从中插入文本和图像的部分照片库有效。我的问题是将该数据从 .sheet 传输到列表。用户插入的 TextFields 中的信息工作正常并显示在列表中,但图像未显示。我不断收到错误消息“无法将‘ImagePickerView’类型的值转换为预期的参数类型‘String’”。我不知道如何解决这个问题。当我尝试插入图像时,这个问题出现在 ContentView.swift 文件中,在 MovieRow 结构中(). 任何帮助将不胜感激。提前致谢。 下面是我的 ContentView 文件。
// 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 文件,用户可以在其中将他们的电影信息插入到 TextField 中,并从他们的照片库中插入图像。这里也是我使用 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,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:
在 Image(uiImage:)
中使用 MovieRow
。 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>) {
//
}
}