有什么方法可以将从ImagePicker选择的图像与在编辑模式下保存的字段相关联?
我有下面的详细视图,该视图显示了从上一个列表视图中选定的记录的生日卡,当单击“编辑”按钮时,显示了字段,我们可以编辑包括配置文件图片的人数据。关键是,除了图像外,单击完成后,所有字段均已正确更新/保存。我相信这是因为编辑模式跟踪更改为ViewContext,而ImagePicker将图像处理为单独的VAR(PIC)。有什么办法可以将图像(var pic)从imagepicker与生日的image.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 = $0 })
TextField("Last Name", text: $birthday.lastName, onEditingChanged: { self.isEditing = $0 })
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 = $0 })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 5)
TextField("Email", text: $birthday.email, onEditingChanged: { self.isEditing = $0 })
.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()
}
}
}
}
上面的代码正确显示了创建记录时保存的数据和图像,它也通过选择另一个映像时在编辑模式时更改图片,但是当单击完成时,除了新图像外,所有更改的数据都保存。 我做了一项庞大的研究,并尝试了许多其他方法,但没有解决这个问题。
有什么想法吗?
imagePicker:
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()
}
}
}
I have the Detail view below which displays the birthday card of a selected record from previous listView and when click into Edit button, the fields are displayed and we can edit the person data including the profile picture. The point is that all the fields are correctly updated/saved when clicking Done after edited except the image. I believe that it is because Edit mode tracks changes into viewContext and the imagePicker is handling the image into a separate var (pic). Is there any way I can associate the image (var pic) from the imagePicker with the birthday.pic field that it’s saved when done editing ?
DetailView:
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 = $0 })
TextField("Last Name", text: $birthday.lastName, onEditingChanged: { self.isEditing = $0 })
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 = $0 })
.textFieldStyle(.roundedBorder)
.padding(.bottom, 5)
TextField("Email", text: $birthday.email, onEditingChanged: { self.isEditing = $0 })
.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()
}
}
}
}
The code above shows correctly the data and image saved when creating the record, it changes the picture when in edit mode by selecting another image also but when clicking done, all changed data is saved except the new image.
I did a huge research and tried many other ways but nothing yet to solve this.
Any ideas ?
ImagePicker:
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()
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,我会这样做,而不是绑定:
在视图中,您可以像这样使用它:
So instead of the binding I would do it like this:
In the view you can use it like this: