LAST CHANCE: Save 50% on all my Swift books and bundles! >>

SOLVED: How to fade out a View immediately after it appears

Forums > SwiftUI

I'm working on something similar to the "Subscribed" notice that appears within the Podcast app.

Subscribed notice in Podcasts

struct FloatingNotice: View {
    var body: some View {
        VStack (alignment: .center, spacing: 8) {
            Image(systemName: "checkmark")
                .foregroundColor(.white)
                .font(.system(size: 48, weight: .regular))
                .padding(EdgeInsets(top: 20, leading: 5, bottom: 5, trailing: 5))
            Text("Review added")
                .foregroundColor(.white)
                .font(.callout)
            .padding(EdgeInsets(top: 0, leading: 10, bottom: 5, trailing: 10))
        }
        .background(Color.snackbar.opacity(0.75))
        .cornerRadius(5)
        .transition(.scale)
        .onAppear {
            withAnimation {
                return self.hidden() // tried self.opacity but that doesn't seem to work either
            }
        }   
    }
}

and I'm presenting my notice from UIKit here

let floatingNotice = UIHostingController(rootView: FloatingNotice())
addChild(floatingNotice)
floatingNotice.view.frame = view.frame
view.addSubview(floatingNotice.view)
floatingNotice.didMove(toParent: self)

I found a pretty simple UIKit way of doing this, but it'd be nice to do this completely from SwiftUI

        UIView.animate(withDuration: 3.0, animations: {
            floatingNotice.view.alpha = 0.0
        }, completion: { success in
            floatingNotice.removeFromParent()
        })

3      

struct ContentView: View {
    @State var showingNotice = false

    var body: some View {
        ZStack {
            Button(action: {
                self.showingNotice = true
            }, label: {
                Text("Show Notice")
            })

            if showingNotice {
                FloatingNotice(showingNotice: $showingNotice)
            }
        }
        .animation(.easeInOut(duration: 1))
    }
}

struct FloatingNotice: View {
    @Binding var showingNotice: Bool

    var body: some View {
        VStack (alignment: .center, spacing: 8) {
            Image(systemName: "checkmark")
                .foregroundColor(.white)
                .font(.system(size: 48, weight: .regular))
                .padding(EdgeInsets(top: 20, leading: 5, bottom: 5, trailing: 5))
            Text("Review added")
                .foregroundColor(.white)
                .font(.callout)
                .padding(EdgeInsets(top: 0, leading: 10, bottom: 5, trailing: 10))
        }
        .background(Color.snackbar.opacity(0.75))
        .cornerRadius(5)
        .transition(.scale)
        .onAppear(perform: {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                self.showingNotice = false
            })
        })
    }
}

How about something like this?

3      

Nice that is perfect. Would you have any suggestions on how to remove this from its parent view when the animation finishes?

3      

Here a slightly difference way

Add these two structs to a file

struct FloatingNoticeView: View {
    var body: some View {
        ZStack {

            BlurView()

            VStack {
                Image(systemName: "checkmark")
                    .font(.largeTitle)
                Text("Added")
                    .padding(.top, 8)
            }
            .foregroundColor(.primary)
        }
        .frame(width: 110, height: 110)
        .cornerRadius(10)
    }
}

struct BlurView: UIViewRepresentable {

    func makeUIView(context: UIViewRepresentableContext<BlurView>) -> UIVisualEffectView {
        let effect = UIBlurEffect(style: .systemThinMaterialDark)
        let view = UIVisualEffectView(effect: effect)
        return view
    }

    func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<BlurView>) {

    }
}

Then in the view that you want the notice to appear add this

struct ContentView: View {
    @State private var showningFloatingView = false

    var body: some View {
        ZStack {
            Button("Add Review") {
                self.showningFloatingView.toggle()
            }

            if showningFloatingView {
                FloatingNoticeView()
                    .onAppear {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                                self.showningFloatingView.toggle()
                        }
                }
                .animation(.easeInOut)
            }
        }
    }
}

Both remove the view after 2 seconds with DispatchQueue.main.asyncAfter(deadline: .now() + 2)

3      

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until July 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.