It is possible to embed SwiftUI views in Swift packages with Swift Package Manager, so they can be distributed, online or internally in your organization, and used across multiple applications.
Benefits
Moving SwiftUI views to libraries has many benefits:
- Improved modularization
- Reduced dependencies
- Improved reusability
- Improved replaceability
- Improved collaboration
Improved Modularization
Modularization brings many benefits, as described below. Putting SwiftUI views in separate modules is a great way to improve modularization.
Reduced Dependencies
Placing views (or any other code) in separate modules forces us into a pattern of removing dependencies. This is good. Having less dependencies means we have to write less interfaces and mocks to test our code.
Improved Reusability
Putting our views (or any other code) in libraries makes it super easy to use them in multiple apps. Specially in the case of open source, we also let other people use our views and libraries in their own projects.
Improved Replaceability
Because of the reduced number of dependencies, replacing views will be much easier down the road. Dependencies are the source of many problems, including making our code hard to replace.
Improved Collaboration
Separating your views from the rest of your application makes it much easier to delegate work. Different developers or even teams can work on separate views and other libraries.
Example
One SwiftUI library I published is Stripes, a simple SwiftUI view to compose stripped backgrounds and other patterns.
Let’s see how to use it in our tool to generate iOS Application Icons with SwiftUI.
Add Stripes Dependency
In the case of the command line tool to generate application icons, I had a Swift package with the command line executable, and also a faux Xcode project for live previews. I will add Stripes to both.
Add Swift Package to the project (for Xcode projects)
Add the library to the target (for Xcode projects)
Add the dependency to the package (for Packages)
let package = Package(
name: "ConsoleUI",
platforms: [
.macOS(.v10_15)
],
products: [
.executable(name: "consoleui", targets: ["ConsoleUI"])
],
dependencies: [
.package(url: "https://github.com/eneko/Stripes", from: "0.2.0")
],
targets: [
.target(name: "ConsoleUI", dependencies: ["Stripes"]),
.testTarget(name: "ConsoleUITests", dependencies: ["ConsoleUI"])
]
)
Use Stripes in our icon generator tool
import SwiftUI
import Stripes
struct MySwiftUIView : View {
let gradientStart = Color(#colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1))
let gradientEnd = Color(#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1))
let petalLength: CGFloat = 400
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [gradientStart, gradientEnd]),
startPoint: .top, endPoint: .bottom)
Stripes(config: StripesConfig(background: Color.white.opacity(0.1),
foreground: Color.white.opacity(0.1),
degrees: 0,
barWidth: 258,
barSpacing: 100))
ForEach(0..<8) { index in
RoundedRectangle(cornerRadius: petalLength / 2)
.frame(width: petalLength, height: petalLength / 2)
.offset(x: petalLength / 2, y: 0)
.opacity(0.4 + 0.05 * Double(index))
.rotationEffect(Angle(degrees: Double(index) * 45))
}
ForEach(0..<8) { index in
Circle()
.frame(width: petalLength / 4, height: petalLength / 4)
.offset(x: petalLength * 0.75, y: 0)
.opacity(0.4 + 0.05 * Double(index))
.rotationEffect(Angle(degrees: Double(index) * 45))
}
}
}
}
Here is the final icon image, from the example above:
This article was written as an issue on my Blog repository on GitHub (see Issue #25)
First draft: 2021-01-24
Published on: 2021-01-24
Last update: 2021-01-24