In my CountrySearch SwiftUI project, I had a requirement to show country flags and the api that i use restCountries , provides me the flag as SVG, I was looking at different options to display SVG image from network.
SourceCode for project: CountrySearchSwiftUI
Below are the solutions I tried
SVGKit is really a nice library but didnt had inbuilt SwiftUI support, so I used a UIViewRepresentable
to make it work, I used the below implementation
import Foundation
import UIKit
import SwiftUI
import SVGKit
struct SVGImageView: UIViewRepresentable {
var url:URL
var size:CGSize
func updateUIView(_ uiView: SVGKFastImageView, context: Context) {
uiView.contentMode = .scaleAspectFit
uiView.image.size = size
}
func makeUIView(context: Context) -> SVGKFastImageView {
let svgImage = SVGKImage(contentsOf: url)
return SVGKFastImageView(svgkImage: svgImage ?? SVGKImage())
}
}
struct SVGImageView_Previews: PreviewProvider {
static var previews: some View {
SVGImageView(url:URL(string:"https://restcountries.eu/data/arg.svg")!, size: CGSize(width: 100,height: 100))
}
}
Usage would be like below in a stack
SVGImageView(url: countryData.imageURL, size: Constants.flagSize)
.frame(width: 50, height: 50, alignment: .center)
.shadow(color: .white, radius: 2)
.border(Color.white, width: 1)
.offset(x: -5, y: 5)
This would display the SVG image. A few additional things I had to care about as well as infer was
a. Had to add explicit size
as CGSize to the SVGImageView so that the svg is correctly sized and on top of that I had to set frame
in the SwiftUI context.
b. Aspect ratio wasnt nice, couldnt find the right api for that from the SDK.
Well and good…., later I wanted to extend my app to watchOS, thats when I realized that SVGKit doesnt seem to work well with watchOS, I was getting a lot of error trying to add it to target and there comes the saviour
As you all know SDWebImage is an awesome library for loading network images optimally and thankfully they have a component built for SwiftUI also. Here is how I integrated it.
- Got rid of Cocoapods :)
- Used Swift Package Manager… added https://github.com/SDWebImage/SDWebImageSwiftUI.git
- To support SVG we need to add SDWebImageSVGCoder ,again using Swift Package Manager
- Add them to both your main target as well as watch OS extension, would look like below
5. In your Appdelegate or App initialize the SVGCoder, If you are using SwiftUI App based project use like this
import SwiftUI
import SDWebImage
import SDWebImageSVGCoder
@main
struct MyApp: App {
let persistenceController = PersistenceController.shared
init() {
setUpDependencies() // Initialize SVGCoder
}
var body: some Scene {
WindowGroup {
MyView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
// Initialize SVGCoder
private extension MyApp {
func setUpDependencies() {
SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
}
}
Now use WebImage
WebImage(url: countryData.imageURL,
context: [.imageThumbnailPixelSize : CGSize.zero])
.resizable()
.frame(width: 50, height: 50)
.shadow(color: .white, radius: 2)
.border(Color.white, width: 1)
.offset(x: -5, y: 5)
And thats all, now you have svg support for both platforms.
References