feedback-assistant / reports

Open collection of Apple Feedback Assistant reports
200 stars 2 forks source link

FB12795690: The lifecycle of a UIViewControllerRepresentable inside a TabView with a PageTabViewStyle is not being called correctly. #411

Open yimajo opened 11 months ago

yimajo commented 11 months ago

Details

Description

When the tabViewStyle modifier for SwiftUI's TabView to something other than normal, the UIViewControllerRepresentable ViewController that configures the TabView will not be able to call viewWillAppear and viewDidAppear.

In other words, the lifecycle methods will not be called properly. This makes it impossible to use UIKit to compensate for the missing parts of the SwiftUI, and also makes it impossible for third-party libraries to work properly.

The sample code that reproduces the problem is as follows, and it reproduces both in Xcode 14.3.1 and Xcode 15 Beta 5. It is also reproduced on both simulators and devices.

import SwiftUI
import UIKit

struct ContentView: View {
    var body: some View {
        TabView {
            SampleView()

            Text("Hello, world!")
        }
        .tabViewStyle(PageTabViewStyle()) // 💥
//        .tabViewStyle(.page) // 💥
//        .tabViewStyle(.page(indexDisplayMode: .always)) // 💥
//        .tabViewStyle(.page(indexDisplayMode: .automatic)) // 💥
//        .tabViewStyle(.page(indexDisplayMode: .never)) // 💥
//        .tabViewStyle(DefaultTabViewStyle()) // no problem.

    }
}

struct SampleView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewControllerType {
        SampleViewController()
    }

    func updateUIViewController(_ uiViewController: SampleViewController, context: Context) {

    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator {}
}

class SampleViewController: UIViewController {
    override func loadView() {
        super.loadView()

        print("loadView")
        let label = UILabel(frame: .init(x: 0, y: 0, width: 100, height: 100))
        label.text = "first"
        label.font = .systemFont(ofSize: 30)
        view.addSubview(label)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        print("willAppear")
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        print("didAppear")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Development environment

Files

mtehsiang commented 7 months ago

I have the exact same issue. I spent four days trying to figure out why my UIViewControllerRepresentable view didn't work as expected. Turns out that viewDidAppear(animated:) is never called, and neither is viewWillAppear(animated:). I wonder if it's because SwiftUI itself provides .onAppear()...

pablichjenkov commented 5 months ago

I am facing the same behavior as @mtehsiang

yimajo commented 4 months ago

I tried with Xcode 15.2 and iOS 17.2.1, but the lifecycle is still not working.

If this is not fixed, I can't use Google AdMob type custom ViewController in SwiftUI.