SwiftUI on macOS, how to use custom image symbol on Button?
Here's my solution, but this is very much of a hack, and I don't know if Apple would approve it. So consider this answer for "educational purposes", I guess.
Concept
The main idea is to modify the SVG file exported by the SF Symbols app so that it only contains one instance of the selected symbol instead of the full template, and to use the SVGKit framework to display it, via an NSViewRepresentable
object.
Export
Use the SF Symbols app on your Mac and select the symbol you want to use, then do "Export Custom Symbol Template".
Modify
Open the exported SVG file in a text editor, such as Sublime Text or CotEditor.
Delete everything in the file except the header and the "Symbols" field, which should only contain the symbol variation you want to use. Then change the size of the rendered canvas and also align the symbol properly.
For example, if you want to use the "Regular-L" version of the "plus" symbol, your final "plus.svg" file should be like this:
<?xml version="1.0" encoding="UTF-8"?>
<!--Generator: Apple Native CoreSVG 123-->
<!DOCTYPE svg
PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128">
<!--glyph: "uni10017C.medium", point size: 100.000000, font version: "Version 15.0d7e11", template writer version: "5"-->
<g id="Symbols">
<g id="Regular-L" transform="matrix(1 0 0 1 0 100)">
<path d="M 67.4316 17.3828 C 70.0684 17.3828 72.2168 15.2832 72.2168 12.7441 L 72.2168 -30.3711 L 114.062 -30.3711 C 116.65 -30.3711 118.848 -32.5684 118.848 -35.1562 C 118.848 -37.793 116.65 -39.9414 114.062 -39.9414 L 72.2168 -39.9414 L 72.2168 -83.1055 C 72.2168 -85.6445 70.0684 -87.7441 67.4316 -87.7441 C 64.8438 -87.7441 62.6953 -85.6445 62.6953 -83.1055 L 62.6953 -39.9414 L 20.8496 -39.9414 C 18.2617 -39.9414 16.0645 -37.793 16.0645 -35.1562 C 16.0645 -32.5684 18.2617 -30.3711 20.8496 -30.3711 L 62.6953 -30.3711 L 62.6953 12.7441 C 62.6953 15.2832 64.8438 17.3828 67.4316 17.3828 Z"/>
</g>
</g>
</svg>
To sum up:
- Keep the header
- Keep the
id="Symbols"
field - In the Symbols field, keep only one category, in my example
id="Regular-L"
- Change the size in the header, in my example
width="128" height="128"
- Align the symbol by changing the last two parameters of the transform field, in my example
transform="matrix(1 0 0 1 0 100)"
(x 0 and y 100)
Install SVGKit
- Close Xcode
- Install SVGKit (https://github.com/SVGKit/SVGKit) using the Cocoapods version
- Open the .xcworkspace file made by Cocoapods
Make a view
Add the modified plus.svg
file to your project (not in the assets catalog, just in the project itself)
Make an NSViewRepresentable
struct like this:
import SVGKit
struct IconView: NSViewRepresentable {
let name: String
func makeNSView(context: Context) -> SVGKFastImageView {
let img = SVGKImage(named: name)!
return SVGKFastImageView(svgkImage: img)!
}
func updateNSView(_ nsView: SVGKFastImageView, context: Context) {
// not implemented
}
}
Use the view
Then use it in your ContentView (give it a frame so that it doesn't fill up the whole window), for example:
struct ContentView: View {
var body: some View {
VStack {
IconView(name: "plus")
.frame(width: 200, height: 200, alignment: .center)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
How to use Symbol Image with Image on macOS 15.15
Seems Symbol Image is not supported on macOS 15.15. The workaround I end up with is converting SF Symbol into SVG and then make them PDF before drag-and-drop in Assets.xcassets
.
Use system icon in SwiftUI with macOS as button
Here it is
Image(nsImage: NSImage(named: NSImage.pathTemplateName)!)
How to increase the icon button of Menu in MacOS App SwiftUI?
Use Image
inText
.
struct DetailView: View {
var body: some View {
Text("hello")
.contextMenu {
Button(action: { }) {
Text(Image(systemName: "gear"))
.font(.largeTitle)
}
Button(action: { }) {
Image(systemName: "gear")
}
}
}
}
SwiftUI: Correct syntax to add a custom Symbol image/SVG to a view?
You can create an Image
from the traditional UIImage(named
syntax
Image(uiImage: UIImage(named: "sausages")!)
Related Topics
Is Dispatchsemaphore a Good Replacement for Nslock
Swiftui: Navigationlink Not Working If Not in a List
Converting Audiobuffer to Cmsamplebuffer with Accurate Cmtime
How to Make Player Move to Opposite Side While Is in a Path
How to Immediately See Swift Errors in Appcode
In What Situation Would One Use Expectationfornotification in Swift Testing
Shared Cookies with Wkprocesspool for Wkwebview in Swift
How to Get a Double Value Up to 2 Decimal Places
Swift String Permutations Allowing the Same Strings
How to Keep a Reference to Another Object in the Parameters of the Class
Iterating Over an Nsorderedset
Gmsplace Returns Invalid Coordinate (-180, -180), But Name and Place Id Are Correct
Swift Progress View with Nstimer
Accurately Get a Color from Pixel on Screen and Convert Its Color Space
Firebase Retrieve Image from Url Save with Firebase Database