I am building an app using SwiftUI where the root view is a tab view with four tabs. One of the app features is the ability to play a podcast while you are browsing through the app. Once the audio begins playing, I want to show a "mini player" with simple start/stop controls, and also track the current progress.
To track progress, I have an @EnvironmentObject injected into the root view, which publishes play time updates, etc. so the mini player can respond. The problem I am finding is that each time the play time value changes, each tab is re-rendered (which is a bad thing) Here is some [simplified] code:
struct ContentView: View {
@EnvironmentObject var playerManager: PlayerManager
var body: some View {
TabView(selection: self.$selection) {
HomeView().tag(0)
View2().tag(1)
View3().tag(2)
View4().tag(3)
}
.overlay(
VStack {
if self.playerManager.showMiniPlayer {
MiniPlayerView()
}
}
)
}
}
class PodcastPlayerManager: NSObject, ObservableObject {
@Published private(set) var elapsedTime = ElapsedTime(progress: 0, duration: 0)
// ... Things happen that cause `elapsedTime` to update
}
I put a log statement in the init() function of View2 and it was being called constantly...which is bad.
My question is whether or not this is the right/best way to model something like this using SwiftUI? I also considered injecting the PlayerManager into the MiniPlayer itself, but I was using a Geometry reader on ContentView to help position the floating MiniPlayer. showMiniPlayer is the only variable from the PlayerManger that I am concerned with in the ContentView... everything else is self-contained within the MiniPlayer View.