TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

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 Superwall.

SPONSORED Superwall lets you build & test paywalls without shipping updates. Run experiments, offer sales, segment users, update locked features and more at the click of button. Best part? It's FREE for up to 250 conversions / mo and the Superwall team builds out 100% custom paywalls – free of charge.

Learn More

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.