SwiftUI: How to fade out a NavigationBarTitle?

Hello together,

after a successful write operation to firebase firestore I want to let the user know, that his data was stored. This shall happen in the Navigation Bar (please see picture).

Simulator Screen Shot - iPhone 12 Pro - 2022-08-22 at 17.52.21

Th green text is managed by a @State property which is set after a successful write operation. The Text appears as intended. But I want to get this text disappear after x seconds with a fade out operation. I tried a couple of solutions with ‘withAnimation’, but didn’t reach the intended result.

Any ideas?

thanks a lot and best regards

Peter

        NavigationView {
            List {
                 ....
                }
            }
            .navigationTitle("Schedule a Game")
            .listStyle(InsetGroupedListStyle())    //GroupedListStyle())
            .toolbar {
                ToolbarItem(placement: .principal) {
                    if showResultText {
                        Text("Game successfully saved")
                            .foregroundColor(Color("IndiansGreen"))
                            .fontWeight(.bold)
                    }
                }
            }
            .navigationBarItems(
                leading: HStack {
                    Button(action: {
                        tabController.open(.home)
                    }, label: {Image(systemName: "arrow.backward")})
                },
                trailing:
                    HStack {
                        Button(action: {
                        }, label: { Text(activateSave ? "Save" : "") })
                        .alert(isPresented: $showAlert) {
                            Alert(
                                title: Text("Warning"),
                                message: Text("Game already exists in database!"),
                                dismissButton: .default(Text("Ok"))
                            )
                        }
                    
                        Button(action: {
                        }, label: {Image(systemName: "trash")})
                    })
            }

@peter_luger

Hi Peter,

Wow this was a bit epic to figure out but I was up for the challenge.

Here is a rearrangement of what you have set up above but in a View to illustrate how I have arrived at a solution.

struct ContentView: View {
    @State private var showResultText = false
    @State private var activateSave = false
    @State private var showAlert = false
    @State private var fadeOpacity = false

    var body: some View {
        NavigationView {
            VStack {
                List(1...10, id: \.self) { item in
                    Text("List item \(item) goes here.")
                }
                HStack(spacing: 40) {
                    Button {
                        showResultText = true
                        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                            withAnimation {
                                fadeOpacity = true
                            }
                        }

                    } label: {
                        Text("Show item Saved")
                    }
                    .disabled(showResultText)

                    Button {
                        showResultText = false
                        fadeOpacity = false
                    } label: {
                        Text("Reset")
                    }
                .listStyle(.plain)
                }    //GroupedListStyle())
            }
            .navigationTitle("Schedule a Game")
            .toolbar {
                ToolbarItem(placement: .principal) {
                    if showResultText {
                        Text("Game successfully saved")
                            .foregroundColor(.green)
                            .fontWeight(.bold)
                            .opacity(fadeOpacity ? 0 : 1)
                    }
                }

                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        // Action
                    } label: {
                        Image(systemName: "arrow.backward")
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    HStack {
                        Button {
                            // Action
                        } label: {
                            Text(activateSave ? "Save" : "")
                        }

                        Button {
                            // Action
                        } label: {
                            Image(systemName: "trash")
                        }
                    }
                }
            }
        }
        .alert(isPresented: $showAlert) {
            Alert(
                title: Text("Warning"),
                message: Text("Game already exists in database!"),
                dismissButton: .default(Text("Ok"))
            )
        }

    }
}

You might note that I spread my code out a bit to make it a bit more readable (at least that’s my preference) and also the .toolbar is configured slightly different to how you did it.

.navigationBarItems has been deprecated so be careful. The correct way to set up toolbar items is as I have done it.

https://developer.apple.com/documentation/swiftui/view/navigationbaritems(leading:trailing:)

Another suggestion could be to animate a new view as a notification, as opposed to using the navigation bar