如何在 Swiftui 上将“ImagePickerView”类型的值转换为预期的参数类型“String”?
Posted
技术标签:
【中文标题】如何在 Swiftui 上将“ImagePickerView”类型的值转换为预期的参数类型“String”?【英文标题】:How to convert value of type 'ImagePickerView' to expected argument type 'String' on Swiftui? 【发布时间】:2021-06-03 17:28:16 【问题描述】:我正在尝试构建一个应用程序,用户可以在其中插入电影的名称,并可以从照片库(使用 UIKit)直接将图像添加到应用程序中。幸运的是,用户可以从中插入文本和图像的部分照片库有效。我的问题是将数据从 .sheet 传输到列表。用户插入的 TextFields 中的信息工作正常并显示在列表中,但图像未显示。我不断收到错误消息“无法将 'ImagePickerView' 类型的值转换为预期的参数类型 'String'”。我不知道如何解决此问题。当我尝试插入图像时,此问题出现在 ContentView.swift 文件中的 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 文件,用户可以在其中将他们的电影信息插入到 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, 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>)
//
【问题讨论】:
这里有这么多代码......将它归结为minimal reproducible example 真的很有帮助。我立即看到的是,您正在尝试使用图像选择器的字符串描述制作Image
(因此是您的错误)。相反,您需要使用 Image(uiImage:)
从您的选择器中使用 selectedImage
。但是,那里的代码太多了,我无法尝试挖掘并弄清楚实际意图是什么。
感谢您的帮助。更具体地说,当我尝试将它添加到我的 MovieAdd 数组时,我试图从 .sheet 获取图像以出现在 ContentView 文件中。提前致谢。
如果您可以将其缩减为重现它所需的代码,我很乐意看看。
@jnpdx 谢谢。我设法把它剪掉了一堆。由于 UIkit 代码,我无法修剪大部分 NewMovieView.swift 文件。但是另外两个文件,我设法修剪了一堆。此外,这些是我使用的仅有的三个文件。让我知道这是否有帮助。谢谢
【参考方案1】:
更改 #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>)
//
【讨论】:
嘿@jnpdx,我听从了你的建议,但是在 struct MovieAdd: Identifiable var id = UUID() var movieName = "" var isComplete : Bool = false var movieImage : UIImage 中,对于 var movieImage: UIImage 我收到一条错误消息“在范围内找不到类型 'UIImage'” 确保import UIKit
以上是关于如何在 Swiftui 上将“ImagePickerView”类型的值转换为预期的参数类型“String”?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Hstack SwiftUI 中将最后一个索引显示为默认值