Reusing view components with ease in SwiftUI
Building components in SwiftUI feels productive; declarative, high-level, and concise code, with instant previews. As you keep building a large enough codebase you also realize the power of component reuse.
The Now Playing Indicator🔗
Muziqi has a now playing indicator that shows if a song or an album in a list is currently playing. It looks like this:
At first, the indicator showed up in several List
s that contained SongRow
s: an album's detail view, playlist's detail view, the all songs list, and a few more. SongRow
was being heavily reused. But a list or a cell being reused is a common pattern in any UI framework.
Concise reuse🔗
Recently I decided to reuse the indicator as part of the button that presents the full visualizer view, to indicate that this is not just any button, but a portal to an exciting, dynamic view! This took me just a single line (alright, it did include the if
statement, so three lines):
Button {
} label: {
// ...
if currentlyPlaing {
NowPlayingIndicator()
}
}
And just like that, I have the view in a completely new context:
Building the NowPlayingIndicator
was fairly easy with a bunch of dynamic Shape
s. But then writing these three lines to get to reuse all of that in a completely new context, felt like magic. I am also super happy with how the dependencies are set up, thanks to EnvironmentObject
.
Dependencies🔗
There is a lot of audio processing shenanigans underneath. A VisualizerDataProcesser
installs a tap on AVAudioPlayerNode, and is computing frequencies and loudness as playback continues. In UIKit land, trying to pass this information to disparate parts of the app is rough; you can either use a singleton or set up dependency injection that makes your Swift code look like Java.
With SwiftUI, EnvironmentObject
makes passing the object a matter of attaching .environmentObject(visualizerDataProcessor)
to a root view. Materializing the object in NowPlayingIndicator
is also a simple matter of @EnvironmentObject var vizProcessor: VisualizerDataProcesser
.
SwiftUI is not without its share of pain, but building a sophisticated app in UIKit would have taken me at least twice as much time with much worse code.