Skip to content

Instantly share code, notes, and snippets.

@alongotv
Last active February 10, 2023 17:21
Show Gist options
  • Save alongotv/7f450e8c47ed3f057e1f6d35443af269 to your computer and use it in GitHub Desktop.
Save alongotv/7f450e8c47ed3f057e1f6d35443af269 to your computer and use it in GitHub Desktop.
Adds viewDidAppear callback to SwiftUI
struct ViewControllerLifecycleHandler: UIViewControllerRepresentable {
func makeCoordinator() -> ViewControllerLifecycleHandler.Coordinator {
Coordinator(onDidAppear: onDidAppear)
}
let onDidAppear: () -> Void
func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerLifecycleHandler>) -> UIViewController {
context.coordinator
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<ViewControllerLifecycleHandler>) {
}
typealias UIViewControllerType = UIViewController
class Coordinator: UIViewController {
let onDidAppear: (() -> Void)?
init(onDidAppear: (() -> Void)?) {
self.onDidAppear = onDidAppear
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
(onDidAppear ?? {})()
}
}
}
struct DidAppearModifier: ViewModifier {
let onDidAppearCallback: (() -> Void)?
func body(content: Content) -> some View {
content
.background(ViewControllerLifecycleHandler(onDidAppear: onDidAppearCallback ?? {}))
}
}
extension View {
func onDidAppear(_ perform: @escaping () -> Void) -> some View {
self.modifier(DidAppearModifier(onDidAppearCallback: perform))
}
}
@Alexminator99
Copy link

Not working for me... I still dont see the animations...

.onDidAppear { withAnimation(.easeOut(duration: 0.5)) { print("IS ANIMATING: \(isAnimating)") isAnimating = true } }

@alongotv
Copy link
Author

@Alexminator99 Are you sure it has something to do with the modifier itself? Have you tried debugging the code to make sure the animation code is called?

If so, could you please provide some technical details (Xcode version, iOS version, Device type: physical or emulator)?

@Alexminator99
Copy link

Alexminator99 commented Dec 29, 2022

Yeah, sure... @alongotv

var body: some View {
        TabView {
            ForEach(0..<5) { item in 
                FruitCardView()
            } //: FOREACH
        } //: TABVIEW
        .tabViewStyle(PageTabViewStyle())
        .padding(.vertical, 20)
    }

// FRUITCARDVIEW
var body: some View {
        ZStack {
            VStack(spacing: 20) {
                // IMAGE
                ...
                // TITLE
                ...
                // HEADLINE
                ...
                // START
                ...
            } //: VSTACK
        } //: ZSTACK
        .onDidAppear {
            withAnimation(.easeOut(duration: 0.5)) {
                print("IS ANIMATING: \(isAnimating)")
                isAnimating = true
            }
        }
        
    }

Where u get this log:

IS ANIMATING: false
IS ANIMATING: false
IS ANIMATING: true
IS ANIMATING: false

As you can see, the 3 view in the TabView is created before it even appears...

@alongotv
Copy link
Author

alongotv commented Dec 29, 2022

@Alexminator99 It looks like something might be broken in TabView once again - I can't receive viewDidAppear callback in the UIViewControllerRepresentable if applied to View inside the TabView (iOS 16.1.1 physical device). Although, viewWillAppear works just fine. Unfortunately, I was unable to find a workaround, other than using that modifier outside the TabView or putting the TabView's child into a ".sheet{}". Either way, it's a pity that this gist wasn't helpful for you. Sorry!

@Alexminator99
Copy link

@Alexminator99 It looks like something might be broken in TabView once again - I can't receive viewDidAppear callback in the UIViewControllerRepresentable if applied to View inside the TabView (iOS 16.1.1 physical device). Although, viewWillAppear works just fine. Unfortunately, I was unable to find a workaround, other than using that modifier outside the TabView or putting the TabView's child into a ".sheet{}". Either way, it's a pity that this gist wasn't helpful for you. Sorry!

I already reported the issue. Thks anyway, the gist is really interesting ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment