有什么方法可以将从 imagePicker 中选择的图像与在编辑模式下保存的字段相关联吗?
Is there any way I can associate the image selected from imagePicker with the field that it’s saved when in Edit mode?
我有下面的详细信息视图,它显示了上一个 listView 中选定记录的生日贺卡,当单击“编辑”按钮时,会显示字段,我们可以编辑个人数据,包括个人资料图片。关键是编辑后单击“完成”时所有字段都正确 updated/saved 除了图像。我相信这是因为编辑模式跟踪 viewContext 的变化,而 imagePicker 正在将图像处理成一个单独的 var (pic)。有什么方法可以将 imagePicker 中的图像 (var pic) 与完成编辑后保存的 birthday.pic 字段相关联?
详细视图:
import SwiftUI
struct BirthdaysDetailView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.editMode) private var editMode
@Environment(\.dismiss) private var dismiss
@ObservedObject var birthday: Nivers
@State private var isEditing: Bool = false
@State private var isShowPhotoLibrary = false
@State private var pic: Data = Data(count: 0)
var body: some View {
VStack {
if editMode?.wrappedValue.isEditing == true {
VStack {
ScrollView {
VStack {
if pic.count != 0 {
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
Image(uiImage: UIImage(data: pic)!)
.resizable()
.aspectRatio(contentMode: .fill)
.mask(Circle())
.overlay(Circle().stroke(Color.text, lineWidth: 2))
.frame(width: 150, height: 150)
.padding(.bottom, 5)
// Cancel Button...
Button(action: { birthday.pic = Data(count: 0) }) {
Image(systemName: "xmark.circle")
.foregroundColor(Color.red)
.padding(6)
.clipShape(Circle())
}
}
.padding(.bottom)
.opacity(1)
} else {
Image(systemName: "person.crop.circle")
.font(.system(size: 50).weight(.ultraLight))
.foregroundColor(Color.text)
.clipped()
}
Button(action: {
self.isShowPhotoLibrary = true
}) {
HStack {
Image(systemName: "photo")
.font(.system(size: 10))
Text("Photo library")
.font(.caption2)
}
.frame(minWidth: 100, minHeight: 20)
.background(Color.text)
.foregroundColor(.white)
.cornerRadius(5)
}
.padding(.bottom, 10)
HStack {
TextField("Name", text: $birthday.name, onEditingChanged: { self.isEditing = [=10=] })
TextField("Last Name", text: $birthday.lastName, onEditingChanged: { self.isEditing = [=10=] })
Button {
birthday.isFavorite = true
} label: {
VStack {
if birthday.isFavorite {
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
.font(Font.system(.caption2, design: .default).weight(.light))
} else {
Image(systemName: "star")
.foregroundColor(Color.yellow)
.font(Font.system(.caption2, design: .default).weight(.light))
}
}
.padding(5)
}
}
.font(.title)
VStack {
DatePicker(selection: $birthday.birthDate, displayedComponents: [.date], label: { Text("Date") })
.labelsHidden()
.datePickerStyle(.graphical)
.frame(width: 250)
TextField("Phone", text: $birthday.phone, onEditingChanged: { self.isEditing = [=10=] })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 5)
TextField("Email", text: $birthday.email, onEditingChanged: { self.isEditing = [=10=] })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 50)
}
.foregroundColor(Color.text)
Spacer()
}
.padding()
.background(Color.background)
}
.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: $pic)
}
}
.navigationBarColor(.systemGray5)
} else {
ZStack {
LottieView(name: "confetti", loopMode: .loop)
.frame(width: 230, height: 250)
VStack {
if let image = birthday.image {
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
image
.resizable()
.aspectRatio(contentMode: .fill)
.mask(Circle())
.frame(width: 150, height: 150)
.clipped()
.padding(.bottom, 5)
}
.padding(.bottom)
.opacity(1)
}
HStack {
Text("\(birthday.name) \(birthday.lastName)")
.font(Font.system(.title, design: .rounded).weight(.heavy))
.padding()
.foregroundColor(Color.primary)
if birthday.isFavorite {
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
.font(Font.system(.callout, design: .default).weight(.medium))
}
}
Text("\(age(date: birthday.birthDate)) years old")
.font(Font.system(.body, design: .rounded).weight(.ultraLight))
.padding(.bottom, 5)
.foregroundColor(Color.primary)
RoundedRectangle(cornerRadius: 30, style: .continuous)
.fill(Color.black.opacity(0.5))
.frame(height: 40)
.clipped()
.padding(.horizontal)
.overlay(Text("\(birthday.birthDate, formatter: itemFormatter)")
.font(Font.system(.body, design: .rounded).weight(.semibold))
.foregroundColor(Color.white), alignment: .center)
if checkBirthdayDates(date: birthday.birthDate) {
Text("TODAY")
.font(Font.system(.caption, design: .rounded).weight(.bold))
.padding()
.foregroundColor(Color.primary)
} else {
Text("\((relativeBirthDate(date: birthday.birthDate)))")
.font(Font.system(.caption, design: .rounded).weight(.light))
.padding()
.foregroundColor(Color.primary)
}
}
}
.padding()
.background(Color.background)
.cornerRadius(20)
.padding(10)
.navigationBarColor(.systemGray5)
}
}
.navigationBarBackButtonHidden(true)
.edgesIgnoringSafeArea(.bottom)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
dismiss()
}) {
Image(systemName: "arrow.backward.square.fill")
.font(.body)
.foregroundColor(Color.text)
}
}
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
.font(.body)
.foregroundColor(Color.text)
}
}
.onReceive(birthday.objectWillChange) { _ in
if viewContext.hasChanges {
try? viewContext.save()
}
}
}
}
上面的代码正确显示了创建记录时保存的数据和图像,它在编辑模式下通过选择另一个图像更改了图片,但是当单击完成时,除了新图像之外所有更改的数据都被保存。
我进行了大量研究并尝试了许多其他方法,但还没有解决这个问题。
有什么想法吗?
图片选择器:
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: Data
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image.jpegData(compressionQuality: 0.1)!
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
所以我会这样做而不是绑定:
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
// @Binding var selectedImage: Data
let completion: (_ selectedImage: UIImage?) -> Void
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.parent.completion(image.jpegData(compressionQuality: 0.1)!)
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
在视图中你可以这样使用它:
ImagePicker(sourceType: .photoLibrary) {newPicture in
//Do what you want here
self.pic = newPicture
}
我有下面的详细信息视图,它显示了上一个 listView 中选定记录的生日贺卡,当单击“编辑”按钮时,会显示字段,我们可以编辑个人数据,包括个人资料图片。关键是编辑后单击“完成”时所有字段都正确 updated/saved 除了图像。我相信这是因为编辑模式跟踪 viewContext 的变化,而 imagePicker 正在将图像处理成一个单独的 var (pic)。有什么方法可以将 imagePicker 中的图像 (var pic) 与完成编辑后保存的 birthday.pic 字段相关联?
详细视图:
import SwiftUI
struct BirthdaysDetailView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.editMode) private var editMode
@Environment(\.dismiss) private var dismiss
@ObservedObject var birthday: Nivers
@State private var isEditing: Bool = false
@State private var isShowPhotoLibrary = false
@State private var pic: Data = Data(count: 0)
var body: some View {
VStack {
if editMode?.wrappedValue.isEditing == true {
VStack {
ScrollView {
VStack {
if pic.count != 0 {
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
Image(uiImage: UIImage(data: pic)!)
.resizable()
.aspectRatio(contentMode: .fill)
.mask(Circle())
.overlay(Circle().stroke(Color.text, lineWidth: 2))
.frame(width: 150, height: 150)
.padding(.bottom, 5)
// Cancel Button...
Button(action: { birthday.pic = Data(count: 0) }) {
Image(systemName: "xmark.circle")
.foregroundColor(Color.red)
.padding(6)
.clipShape(Circle())
}
}
.padding(.bottom)
.opacity(1)
} else {
Image(systemName: "person.crop.circle")
.font(.system(size: 50).weight(.ultraLight))
.foregroundColor(Color.text)
.clipped()
}
Button(action: {
self.isShowPhotoLibrary = true
}) {
HStack {
Image(systemName: "photo")
.font(.system(size: 10))
Text("Photo library")
.font(.caption2)
}
.frame(minWidth: 100, minHeight: 20)
.background(Color.text)
.foregroundColor(.white)
.cornerRadius(5)
}
.padding(.bottom, 10)
HStack {
TextField("Name", text: $birthday.name, onEditingChanged: { self.isEditing = [=10=] })
TextField("Last Name", text: $birthday.lastName, onEditingChanged: { self.isEditing = [=10=] })
Button {
birthday.isFavorite = true
} label: {
VStack {
if birthday.isFavorite {
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
.font(Font.system(.caption2, design: .default).weight(.light))
} else {
Image(systemName: "star")
.foregroundColor(Color.yellow)
.font(Font.system(.caption2, design: .default).weight(.light))
}
}
.padding(5)
}
}
.font(.title)
VStack {
DatePicker(selection: $birthday.birthDate, displayedComponents: [.date], label: { Text("Date") })
.labelsHidden()
.datePickerStyle(.graphical)
.frame(width: 250)
TextField("Phone", text: $birthday.phone, onEditingChanged: { self.isEditing = [=10=] })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 5)
TextField("Email", text: $birthday.email, onEditingChanged: { self.isEditing = [=10=] })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 50)
}
.foregroundColor(Color.text)
Spacer()
}
.padding()
.background(Color.background)
}
.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: $pic)
}
}
.navigationBarColor(.systemGray5)
} else {
ZStack {
LottieView(name: "confetti", loopMode: .loop)
.frame(width: 230, height: 250)
VStack {
if let image = birthday.image {
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
image
.resizable()
.aspectRatio(contentMode: .fill)
.mask(Circle())
.frame(width: 150, height: 150)
.clipped()
.padding(.bottom, 5)
}
.padding(.bottom)
.opacity(1)
}
HStack {
Text("\(birthday.name) \(birthday.lastName)")
.font(Font.system(.title, design: .rounded).weight(.heavy))
.padding()
.foregroundColor(Color.primary)
if birthday.isFavorite {
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
.font(Font.system(.callout, design: .default).weight(.medium))
}
}
Text("\(age(date: birthday.birthDate)) years old")
.font(Font.system(.body, design: .rounded).weight(.ultraLight))
.padding(.bottom, 5)
.foregroundColor(Color.primary)
RoundedRectangle(cornerRadius: 30, style: .continuous)
.fill(Color.black.opacity(0.5))
.frame(height: 40)
.clipped()
.padding(.horizontal)
.overlay(Text("\(birthday.birthDate, formatter: itemFormatter)")
.font(Font.system(.body, design: .rounded).weight(.semibold))
.foregroundColor(Color.white), alignment: .center)
if checkBirthdayDates(date: birthday.birthDate) {
Text("TODAY")
.font(Font.system(.caption, design: .rounded).weight(.bold))
.padding()
.foregroundColor(Color.primary)
} else {
Text("\((relativeBirthDate(date: birthday.birthDate)))")
.font(Font.system(.caption, design: .rounded).weight(.light))
.padding()
.foregroundColor(Color.primary)
}
}
}
.padding()
.background(Color.background)
.cornerRadius(20)
.padding(10)
.navigationBarColor(.systemGray5)
}
}
.navigationBarBackButtonHidden(true)
.edgesIgnoringSafeArea(.bottom)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
dismiss()
}) {
Image(systemName: "arrow.backward.square.fill")
.font(.body)
.foregroundColor(Color.text)
}
}
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
.font(.body)
.foregroundColor(Color.text)
}
}
.onReceive(birthday.objectWillChange) { _ in
if viewContext.hasChanges {
try? viewContext.save()
}
}
}
}
上面的代码正确显示了创建记录时保存的数据和图像,它在编辑模式下通过选择另一个图像更改了图片,但是当单击完成时,除了新图像之外所有更改的数据都被保存。 我进行了大量研究并尝试了许多其他方法,但还没有解决这个问题。
有什么想法吗?
图片选择器:
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: Data
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image.jpegData(compressionQuality: 0.1)!
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
所以我会这样做而不是绑定:
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
// @Binding var selectedImage: Data
let completion: (_ selectedImage: UIImage?) -> Void
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.parent.completion(image.jpegData(compressionQuality: 0.1)!)
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
在视图中你可以这样使用它:
ImagePicker(sourceType: .photoLibrary) {newPicture in
//Do what you want here
self.pic = newPicture
}