TabView Swift UI bug keyboard in scrollview

I have an app that contains a TabView component in SwiftUI. My tabs contain both views that are in SwiftUI and UIViewControllers that use the UIViewRepresentable.

However, if I use a text field in a ScrollView component, when opening the keyboard, a "White View" appears behind the keyboard, almost imperceptible. It happens both on iOS 14 to the latest 16.4. Has anyone experienced this or is it really a SwiftUI bug?

Here is code and evidence for example:

struct View1: View {
    @State private var fields: [String] = Array(repeating: "", count: 100)

    var body: some View {
        VStack {
            ScrollView {
                ForEach(0..<fields.count, id: \.self) { index in
                    TextField("Campo \(index + 1)", text: $fields[index])
                        .padding()
                        .background(Color.gray.opacity(0.2))
                        .cornerRadius(10)
                }
            }
            .onTapGesture {
                hideKeyboard()
            }
            .padding()
        }
    }

    private func hideKeyboard() {
        UIApplication.shared.sendAction(
            #selector(UIResponder.resignFirstResponder),
            to: nil,
            from: nil,
            for: nil
        )
    }
}

struct ContentView: View {
    var body: some View {
        TabView {
            View1()
                .tabItem {
                    Label("Explorar", systemImage: "tray.and.arrow.down.fill")
                }

            ViewControllerWrapper()
                .tabItem {
                    Label("Anunciar", systemImage: "tray.and.arrow.down.fill")
                }
            
        }
    }
}

UIViewController in UiKit

import UIKit
import SwiftUI

struct ViewControllerWrapper: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> ViewController {
        return ViewController()
    }

    func updateUIViewController(_ uiViewController: ViewController, context: Context) {}
}

class ViewController: UIViewController {

    let scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        return scrollView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        setupScrollView()
        addTextFields()
        setupTapGesture()
    }

    private func setupScrollView() {
        view.addSubview(scrollView)
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

    private func addTextFields() {
        var previousTextField: UITextField?

        for i in 0..<100 {
            let textField = UITextField()
            textField.placeholder = "Campo \(i+1)"
            textField.borderStyle = .roundedRect
            textField.translatesAutoresizingMaskIntoConstraints = false
            scrollView.addSubview(textField)

            NSLayoutConstraint.activate([
                textField.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 20),
                textField.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -20),
                textField.heightAnchor.constraint(equalToConstant: 40),
            ])

            if let previous = previousTextField {
                textField.topAnchor.constraint(equalTo: previous.bottomAnchor, constant: 10).isActive = true
            } else {
                textField.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 20).isActive = true
            }

            previousTextField = textField
        }

        if let lastTextField = previousTextField {
            lastTextField.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -20).isActive = true
        }
    }

    private func setupTapGesture() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

    @objc private func handleTap() {
        view.endEditing(true)
    }
}

Hi Luis,

Bugs in Apple’s proprietary frameworks, such as UIKit and SwiftUI, are reported through Feedback Assistant.

1 Like

thanks! I will report it!