How to display Image from a url in SwiftUI
iOS 15 update:
you can use asyncImage in this way:AsyncImage(url: URL(string: "https://your_image_url_address"))
more info on Apple developers document:
AsyncImage
Using ObservableObject (Before iOS 15)
first you need to fetch image from url :
class ImageLoader: ObservableObject {
var didChange = PassthroughSubject<Data, Never>()
var data = Data() {
didSet {
didChange.send(data)
}
}
init(urlString:String) {
guard let url = URL(string: urlString) else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
DispatchQueue.main.async {
self.data = data
}
}
task.resume()
}
}
you can put this as a part of your Webservice class function too.
then in your ContentView struct you can set @State image in this way :
struct ImageView: View {
@ObservedObject var imageLoader:ImageLoader
@State var image:UIImage = UIImage()
init(withURL url:String) {
imageLoader = ImageLoader(urlString:url)
}
var body: some View {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:100, height:100)
.onReceive(imageLoader.didChange) { data in
self.image = UIImage(data: data) ?? UIImage()
}
}
}
Also, this tutorial is a good reference if you need more
SwiftUI Image from URL not showing
Try using @Published
- then you don't need a custom PassthroughSubject
:
class ImageLoader: ObservableObject {
// var didChange = PassthroughSubject<Data, Never>() <- remove this
@Published var data: Data?
...
}
and use it in your view:
struct ImageView: View {
var urlString: String
@ObservedObject var imageLoader = ImageLoader()
@State var image = UIImage(named: "homelessDogsCats")!
var body: some View {
ZStack() {
Image(uiImage: image)
.resizable()
.onReceive(imageLoader.$data) { data in
guard let data = data else { return }
self.image = UIImage(data: data) ?? UIImage()
}
}.onAppear {
self.imageLoader.loadData(from: urlString)
}
}
}
Note: if you're using SwiftUI 2, you can use @StateObject
instead of @ObservedObject
and onChange
instead of onReceive
.
struct ImageView: View {
var urlString: String
@StateObject var imageLoader = ImageLoader()
@State var image = UIImage(named: "homelessDogsCats")!
var body: some View {
ZStack() {
Image(uiImage: image)
.resizable()
.onChange(of: imageLoader.data) { data in
guard let data = data else { return }
self.image = UIImage(data: data) ?? UIImage()
}
}.onAppear {
self.imageLoader.loadData(from: urlString)
}
}
}
How to display image from known image path - SwiftUI
You say NSOpenPanel
, so I'm making going to make the assumption here that we don't need to worry about waiting to load the image over a network:
if let nsImage = NSImage(contentsOf: url) {
Image(nsImage: nsImage)
}
How to display an image in SwiftUI protected by header-based authentication
You just need replace AsyncImage component with your own component. I created this component, is similar to AsyncImage but this receives a custom async function to get the image
struct CustomAsyncImage<Content: View, Placeholder: View>: View {
@State var uiImage: UIImage?
let getImage: () async -> UIImage?
let content: (Image) -> Content
let placeholder: () -> Placeholder
init(
getImage: @escaping () async -> UIImage?,
@ViewBuilder content: @escaping (Image) -> Content,
@ViewBuilder placeholder: @escaping () -> Placeholder
){
self.getImage = getImage
self.content = content
self.placeholder = placeholder
}
var body: some View {
if let uiImage = uiImage {
content(Image(uiImage: uiImage))
}else {
placeholder()
.task {
self.uiImage = await getImage()
}
}
}
}
This is an example of use.
CustomAsyncImage(getImage: getImage) { image in
image
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity)
} placeholder: {
Text("PlaceHolder")
}
Where getImage is an async function that return an UIImage, you can make that function as you want.
I gonna show you my function as example.
func getImage() async -> UIImage? {
guard let url = URL(string: BASE_URL + "cards/5fd36d31937b6b32d47ad9db/attachments/5fd36d31937b6b32d47ad9de/download") else {
fatalError("Missing URL")
}
var request = URLRequest(url: url)
request.addValue("OAuth oauth_consumer_key=\"\(API_KEY)\", oauth_token=\"\(ACCOUNT_TOKEN)\"", forHTTPHeaderField: "Authorization")
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching attchment") }
return UIImage(data: data)
} catch {
return nil
}
}
Loading/Downloading image from URL on Swift
Xcode 8 or later • Swift 3 or later
Synchronously:
if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
imageView.contentMode = .scaleAspectFit
imageView.image = image
}
Asynchronously:
Create a method with a completion handler to get the image data from your url
func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}
Create a method to download the image (start the task)
func downloadImage(from url: URL) {
print("Download Started")
getData(from: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
// always update the UI from the main thread
DispatchQueue.main.async() { [weak self] in
self?.imageView.image = UIImage(data: data)
}
}
}
Usage:
override func viewDidLoad() {
super.viewDidLoad()
print("Begin of code")
let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")!
downloadImage(from: url)
print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}
Extension:
extension UIImageView {
func downloaded(from url: URL, contentMode mode: ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
Usage:
imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")
How can i return images from assets instead of systemName Image and call it in the body Using swiftui
You can do it with an Image Set
, an @ViewBuilder
.
struct CustomImageView: View {
var body: some View {
Symbols.info.image()
}
enum Symbols: String, CaseIterable{
case info
case success
case warning
case error
var sfSymbolName: String{
switch self {
case .info:
return "info.circle"
case .success:
return "checkmark.seal"
case .warning:
return "exclamationmark.octagon"
case .error:
return "xmark.octagon"
}
}
///Name must exactly match an `Image Set` in `Assets`
///Project Navigator > Assets > + > Image Set >
var assetsName: String{
switch self {
case .info:
return "NameFromAssetsImageSet_info"
case .success:
return "NameFromAssetsImageSet_success"
case .warning:
return "NameFromAssetsImageSet_warning"
case .error:
return "NameFromAssetsImageSet_error"
}
}
@ViewBuilder func image() -> some View {
let showFromAssets: Bool = true
switch showFromAssets{
case true:
Image(assetsName)
case false:
Image(systemName: sfSymbolName)
}
}
}
}
Related Topics
How to Draw a Cosine or Sine Curve in Swift
Firebase Completion Listeners in Swift
Swiftui: How to Make Entire Shape Recognize Gestures When Stroked
Nsimage Getting Resized When I Draw Text on It
If the Swift 'Guard' Statement Must Exit Scope, What Is the Definition of Scope
Nested Types in Swift - What Is the Good Practice
Uipickerview Selectrow Doesn't Works
Scenekit - Custom Geometry Does Not Show Up
Declare Array of Classes That Conform to a Protocol
Why Does the Following Code Crash on an iPhone 5 But Not an iPhone 5S
Detect Left and Right Click Events on Nsstatusitem (Swift)
How to Use Trailing Closure in If Condition
Compare Three Values for Equality
Swift Struct Initialization, Making Another Struct Like String