Display SVG in SwiftUI (iOS/ WatchOS)

anoop m
3 min readFeb 3, 2021

--

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

  1. SVGKit

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

2. SDWebImageSwiftUI

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.

  1. Got rid of Cocoapods :)
  2. Used Swift Package Manager… added https://github.com/SDWebImage/SDWebImageSwiftUI.git
  3. To support SVG we need to add SDWebImageSVGCoder ,again using Swift Package Manager
  4. 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

https://github.com/SDWebImage/SDWebImageSwiftUI/issues/129

--

--

No responses yet