How to prevent SwiftUI to rerender the entire tabview when using a Custom Alert view on top of it?

Viewed 85

I have a tab view with 5 tabs. An alert view will be shown at the top when my view model's property gets true? But every time the alert is shown, the entire tab view is redrawn causing high cpu usage.

I want the alert to be shown regardless of which tab the user is in so I did a ZStack on the tab view to show the alert. But how do I prevent SwiftUI to redraw the entire tab view?

struct ContentView: View {
    var body: some View {
        ZStack {
            TabView() {
                MiniPlayer(content:
                    BrowseView()
                )
                .tabItem {
                    Group {
                        Image(systemName: "square.grid.2x2")
                        Text("Browse")
                    }
                    .onTapGesture {
                        selectedTab = 0
                    }
                }
                .tag(0)
                
                MiniPlayer(content:
                    AllSongsListView()
                )
                .tabItem {
                    Group {
                        Image(systemName: "music.note")
                        Text("Songs")
                    }
                    .onTapGesture {
                        selectedTab = 1
                    }
                }
                .tag(1)
                
                MiniPlayer(content:
                    PlaylistsView()
                )
                .tabItem {
                    Group {
                        Image(systemName: "music.note.list")
                        Text("Playlists")
                    }
                    .onTapGesture {
                        selectedTab = 2
                    }
                }
                .tag(2)
                
                MiniPlayer(content:
                    MoreView()
                )
                .tabItem {
                    Group {
                        Image(systemName: "ellipsis")
                        Text("More")
                    }
                    .onTapGesture {
                        selectedTab = 3
                    }
                }
                .tag(3)
            }
            
            Alert()
        }
        .ignoresSafeArea(.keyboard)
    }
}

struct Alert: View {
    @EnvironmentObject var manager: Manager
    
    var body: some View {
        if manager.showSuccessAlert {
            VStack {
                VStack {
                    Text("Successful.")
                        .font(.system(size: 20, weight: .bold, design: .rounded))
                        .multilineTextAlignment(.center)
                }
                .frame(height: 50)
                .frame(maxWidth: .infinity)
                .foregroundColor(.white)
                .background(Color.blue)
                .clipShape(Capsule())
                
                Spacer()
            }
            .zIndex(1)
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
                    withAnimation {
                        
                        manager.showSuccessAlert = false
                    }
                }
            }
            .transition(.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .top)))
        }
    }
}
1 Answers

Try to move entire TabView into separated view, so that ZStack looks like

    ZStack {
       TabsContentView()      // << move everything inside !!
       Alert()
    }
Related