Asset symbol generation in Swift Package
Asked Answered
A

2

8

I have a Swift Package in my SwiftUI project that includes styles for UI components. Also, this package includes a resource folder that contains assets that can be used in styling. I can get an image by its name but I would like to know if I could access images with enums. Because Xcode 15 automatically generates symbols for assets.

The following example would explain what I mean:

public struct CheckboxToggleStyle: ToggleStyle {
@Binding var color: Color

let checked = Image("checkbox-checked", bundle: .module) // ✅ works
let unchecked = Image("checkbox-unchecked", bundle: .module) // ✅ works
let checked = Image(.checkboxChecked) // ❌ failed
let unchecked = Image(.checkboxUnchecked) // ❌ failed

public func makeBody(configuration: Configuration) -> some View {
    (configuration.isOn ? checked : unchecked)
        .renderingMode(.template)
        .foregroundColor(color)
        .onTapGesture {
            withAnimation {
                configuration.isOn.toggle()
            }
        }
}

}

Allonym answered 17/7, 2023 at 13:36 Comment(4)
Which version of Swift? for instance release notes for Resolved Issues in Xcode 15 Beta 3 states "Fixed: Asset symbols are now generated for assets in Swift packages. (110083791)" So you may need to update to that versionAudacious
It is Swift 5.9 but I use Xcode 15 Beta 1. I'll try with Beta 3Allonym
Did you manage to make it work with the latest Beta ? I am still not able to make it work :/Sargassum
No, this issue still persists 😕 @GrzegorzKrukowskiAllonym
J
-4

Here's how I do it. If you want more details feel free to look at my package Iconoir at https://github.com/iconoir-icons/iconoir-swift/tree/main

Ultimately, what you'll need to do it define an enum of whatever name, and then assign all of the respective Symbol Names as strings to the enum, then follow up with a utility method or enum computed property. You could, in theory, also write a script that will automatically grab all symbol names and generate the enum for you, that's what I ended up doing with Iconoir as there's no way I'm manually typing 1000+ enum declarations.

Enum

public enum Iconoir: String, CaseIterable {
    case bell = "bell"

Implementation

@available(iOS 13, macOS 10.15, *)
public extension Iconoir {
    /// Returns a SwiftUI Image of the Iconoir icon.
    var asImage: Image {
        return Image(self.rawValue, bundle: Bundle.module)
            .renderingMode(.template)
    }
    
    
    /// Returns an image, from the Iconoir bundle, if there is a matching key.
    /// - Parameter string: key that matches iconoir icon.
    /// - Returns: SwiftUI Image
    static func image(from string: String) -> Image {
        return Image(string, bundle: Bundle.module)
            .renderingMode(.template)
    }
}
#endif

Usage

Iconoir.bell.asImage
Iconoir.bell.asUIImage
Iconoir.image(from: "bell")

Other Thoughts

If you don't have too many images, rather than creating an extension like I've done, you can simply add a computed property that does a similar thing, to your enum.

var image: Image { 
    //... 
}
Jabber answered 17/7, 2023 at 14:45 Comment(0)
P
-5

Correct syntax is Image(resource: .checkboxChecked) (not Image(.checkboxChecked))

Pirbhai answered 14/9, 2023 at 22:23 Comment(1)
No it's not. It's UIImage(resource: .checkboxChecked) in UIKit but Image(.checkboxChecked) in SwiftUI.Inseparable

© 2022 - 2024 — McMap. All rights reserved.