So I am working on users uploading images to a "profile picture" of sorts. So my image picker I believe is working fine. The issue is it uploads, but the default image still shows initially.
I know this because if I go to upload another image, for a brief moment the default picture disappears and the new uploaded image can be seen. My button triggers the showingImagePicker bool which shows the new image and should hide the default image, I don't understand why the default image would still be showing.
struct RecipeEditorImage: View {
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
@State private var image: Image?
var body: some View {
ZStack (alignment: .trailing){
if showingImagePicker{
image?
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:200, height: 100)
}
else{
Image("ExampleRecipePicture")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:200, height: 100)
}
Image(systemName:("plus.circle.fill")).renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fill)
.offset(x: 20)
.foregroundColor(Color("completeGreen"))
.frame(width:50, height:10)
.onTapGesture {
showingImagePicker = true
}
.sheet(isPresented: $showingImagePicker){
EditorImagePicker(image: $inputImage)
}
.onChange(of: inputImage){ _ in loadImage() }
}
}
func loadImage(){
guard let inputImage = inputImage else { return }
image = Image(uiImage: inputImage)
}
}
import PhotosUI
import SwiftUI
struct EditorImagePicker: UIViewControllerRepresentable{
@Binding var image: UIImage?
class Coordinator: NSObject, PHPickerViewControllerDelegate{
var parent: EditorImagePicker
init(_ parent: EditorImagePicker){
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let provider = results.first?.itemProvider else { return }
if provider.canLoadObject(ofClass: UIImage.self){
provider.loadObject(ofClass: UIImage.self){image, _ in
self.parent.image = image as? UIImage
}
}
}
}
func makeUIViewController(context: Context) -> PHPickerViewController {
//configures ios to just be able to select images
var config = PHPickerConfiguration()
config.filter = .images
//the view of picker
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
//leave empty for now
}
}
CodePudding user response:
There are a few issues:
Your first
if
clause guarantees the chosen image will only be shown if the sheet is shown as well.You probably want to avoid the extra step of storing a reference to the
Image
View
-- just use it dynamically. That gets rid of theonChange
as well.Your
loadObject
closure needs to call back to the main thread.
import SwiftUI
import PhotosUI
struct RecipeEditorImage: View {
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
var body: some View {
ZStack (alignment: .trailing){
if let inputImage = inputImage {
Image(uiImage: inputImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:200, height: 100)
} else{
Image(systemName: "pencil")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:200, height: 100)
}
Image(systemName:("plus.circle.fill")).renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fill)
.offset(x: 20)
.foregroundColor(Color("completeGreen"))
.frame(width:50, height:10)
.contentShape(Rectangle())
.onTapGesture {
showingImagePicker = true
}
.sheet(isPresented: $showingImagePicker){
EditorImagePicker(image: $inputImage)
}
}
}
}
struct EditorImagePicker: UIViewControllerRepresentable{
@Binding var image: UIImage?
class Coordinator: NSObject, PHPickerViewControllerDelegate{
var parent: EditorImagePicker
init(_ parent: EditorImagePicker){
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let provider = results.first?.itemProvider else { return }
if provider.canLoadObject(ofClass: UIImage.self){
provider.loadObject(ofClass: UIImage.self){image, _ in
DispatchQueue.main.async {
self.parent.image = image as? UIImage
}
}
}
}
}
func makeUIViewController(context: Context) -> PHPickerViewController {
//configures ios to just be able to select images
var config = PHPickerConfiguration()
config.filter = .images
//the view of picker
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
//leave empty for now
}
}