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 Lists that contained SongRows: 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 Shapes. 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.