I am experimenting with using ContentMenu
to allow users to do things such as saving images to their camera roll. Currently in the code, the value of the displayed image is of type Image
so I made a function that’s supposed to convert it into a value of type UIImage
and then the image would be saved to the camera roll via UIImageWriteToSavedPhotosAlbum()
. The code works, however when I go to view the saved image in the camera roll it appears as an all-black image, rather than the actual image itself.
The code for the conversion is as follows:
extension Image {
func asUIImage() -> UIImage? {
// Create a UIView
let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
// Create a hosting controller with the SwiftUI Image
let hostingController = UIHostingController(rootView: self)
// Assign the frame to the hosting controller
hostingController.view.frame = uiView.bounds
// Add the hosting controller's view to the UIView
uiView.addSubview(hostingController.view)
// Make the snapshot of the hosting controller's view
UIGraphicsBeginImageContextWithOptions(uiView.bounds.size, uiView.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
uiView.layer.render(in: context)
let uiImage = UIGraphicsGetImageFromCurrentImageContext()
return uiImage
}
}
which is called here:
func manyMediaView(media: [MediaOBJ]) -> some View {
GeometryReader { geo in
TabView {
ForEach(media.indices, id: \.self) { index in
AsyncImage(url: media[index].link) { phase in
switch phase {
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fill)
.contentShape(Rectangle())
.onTapGesture {
selectedImageIndex = index
showFullImage = true
}
.contextMenu {
Button(action: {
// Action to copy the photo
}) {
Text("Copy Photo")
Image(systemName: "doc.on.doc")
}
Button(action: {
// Action to save the photo
if let uiImage = image.asUIImage() {
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
print("Saved successfully!")
} else {
print("Error: Unable to convert Image to UIImage.")
}
}) {
Text("Save Photo")
Image(systemName: "square.and.arrow.down")
}
ShareLink(item: viewModel.post.url) {
Text("Share via ...")
Image(systemName: "square.and.arrow.up")
}
}
case .failure:
DefaultPlaceholder()
.maxHeight(600)
.onAppear {
imageLoadKey = .init()
}
case .empty:
Color.clear
}
}
.tag(index)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.cornerRadius(16)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.gesture(
DragGesture().onChanged { value in
if value.translation.width > 50 {
selectedImageIndex = max(selectedImageIndex - 1, 0)
} else if value.translation.width < -50 {
selectedImageIndex = min(selectedImageIndex + 1, media.count - 1)
}
}
)
.fullScreenCover(isPresented: $showFullImage) {
MultiImageGalleryView(imageUrls: media.map { $0.link }, isPresented: $showFullImage, selectedImageIndex: $selectedImageIndex)
}
.onTapGesture {
// Intentionally empty to prevent auto navigation to SinglePostView
}
}
}
What am I missing that’ll let the images be properly saved?