2

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()
            }
        }
}

}

Dogan Altinbas
  • 268
  • 2
  • 11
  • 1
    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 version – timbre timbre Jul 17 '23 at 13:46
  • It is Swift 5.9 but I use Xcode 15 Beta 1. I'll try with Beta 3 – Dogan Altinbas Jul 17 '23 at 13:49

1 Answers1

0

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 { 
    //... 
}
xTwisteDx
  • 2,152
  • 1
  • 9
  • 25