Goal: SwiftUI Image on Multiplatform iOS/MacOS
Problem: when loading Image I need to wrap into an UIImage, and it won't work on macOS
Question: How can I worth with loading images that are Multiplatform?
var body: some View {
Image(uiImage: UIImage(data: image ?? self.image)!)
}
Add a helper file only available to your macOS target that includes this:
typealias UIImage = NSImage
extension Image {
init(uiImage: UIImage) {
self.init(nsImage: uiImage)
}
}
There are some limitations to this approach, as UIImage and NSImage don't share all the same methods and initializers, but it will work for basic cases like the one you mentioned in your question (init(data: ))
A safer version of this (if you're willing to rewrite some of your UIImage inits) might be to create a custom type eg MyImage that is aliased to NSImage on macOS and UIImage on iOS. That way you'll at least have a reminder in your code that you're not actually calling UIImage on macOS.
Related
I want to display a QR code in SwiftUI. The code is generated as a CGImage via CIImage. I don't want to scale it to the full size available because if the scaling factor isn't an integer there may be fuzzy boundaries between the QR modules. So I need a way to convert between iOS display points which I can get with GeometryReader and physical points. I've found a few search "hits" about reading the screen scale from a UIView, but not how I can get this scale in SwiftUI.
There a few more hits which just say the scale is 3 on all modern iPhones, and as I'm targeting iOS 15+ I think I can safely assume it's always 3 for now, but what if Apple bring out even higher pixel densities in future?
You can get displayScale using the Environment property wrapper.
struct ContentView: View {
#Environment(\.displayScale) var displayScale
var body: some View {
Text("display scale: \(displayScale)")
}
}
Consult EnvironmentValues to what else SwiftUI provides in the “environment”.
I am downloading a JPG image from a remote server. If I use AsyncImage, portrait images taken from the phone's library are rotated 90 degrees. Landscape images taken from the phone's photo library are fine. Also, portrait and landscape photos taken from the phone's camera are fine. Looking at the image on a computer using the URL renders in the correct orientation. If, instead of using AsyncImage to display the image, I instead download it as Data and convert it to a UJIImage, it works fine. So this is only an issue when using AsyncImage. How can I prevent portrait images from rotating 90 degrees while still using AsyncImage?
VStack {
AsyncImage(url: imageURL, transaction: Transaction(animation: .spring())) { phase in
switch phase {
case .empty:
Color.purple.opacity(0.1)
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fill)
.transition(.scale)
case .failure(_):
Image(systemName: "exclamationmark.icloud")
.resizable()
.scaledToFit()
#unknown default:
Image(systemName: "exclamationmark.icloud")
}
}
.frame(width: 200, height: 250)
.cornerRadius(10)
}
Update: Although this doesn't specifically answer the question on AsyncImage I was able to get around this issue by performing a transform on the image before it is sent to the server. I know there are issues of orientation when sending as PNG; however, I was sending using jpgData from a UIImage. However, I applied this transform anyway before sending and it worked when receiving via AsyncImage. As a UIImage it would have been fine so some internal process within AsyncImage is handling it differently and thus this additional transform that is otherwise not required for UIImage or any other platform, is required in this instance. Perhaps that is simply the answer, but I'll leave it as is given the question is about the behavior of AsyncImage.
i'm in need to force the orientation of the interface in landscape is the app runs in an iPad device.
I have found some code in stackoverflow that call
let value = UIInterfaceOrientation.landscapeRight.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
in a buttons and it should force the orientation of the device but i experienced no change in my app. the set to landscaperight does absolutely nothing.
How can i achieve the rotation?
I've encountered what I think is a bug, and I'm wondering if anyone else has encountered this, and/or has a work around for it.
I have images imported from the device's camera via the UIImagePickerController representable. Having imported this image, I then save it to the documents directory, and then display it using the following code:
Image(uiImage: image)
.resizable()
.frame(height: 300)
.scaledToFill()
This shouldn't cause the image to distort, as scaled to fill should simply enlarge the image until it fits the frame without distorting it. However, i'm getting a fair amount of horizontal stretching in the final image:
Has anyone encountered this problem? I don't think i'm missing anything obvious, as when I use it for images not taken with the camera then the code performs fine.
Try changing the order of the modifiers as below,
Image(uiImage: UIImage(named: "08-512")!)
.resizable()
.scaledToFill()
.frame(width: 50, height: 20)
//.clipped()
}
Usually you would use a custom view and the draw(rect:) method within in it to draw paths but since I don't have UIViews (and don't want to use UIKit integration) where can I draw?
You would use the GeometryReader and the Path
return GeometryReader { geometry in
Path { path in
path.addPath(...)
}
}
Apple Developer Documentation
And a Swift Tutorial on that topic also by Apple