Swift 5 | UINavigationController 直到转到 DetailsViewController 才出现

Swift 5 | UINavigationController not appearing until going to DetailsViewController

我正在努力以编程方式重建我的应用程序,而不是使用情节提要和 运行 解决我的 UINavigationController 问题。当应用程序首次加载根 ViewController 时,包含 "carrier" 的栏和时间是我分配的颜色的浅色版本,并且存在搜索栏而不是普通导航栏。

当我 tap/click 我的 UITableView 上的一个单元格进入详细信息屏幕然后返回时,我的 UINavigationBar 正确显示但搜索栏消失了。我确定我混淆了一些东西,但我不确定我在哪里搞砸了或者我是否完全遗漏了一些东西。任何和所有帮助将不胜感激。我还附上了一张图片作为示例。

Nonexistant UINavigationController > Detail screen > Back.gif

我在 SceneDelegate 中设置了一个 TabBarController 场景代理

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// MARK: - Properties
var window: UIWindow?
let tabBarDelegate = TabBarDelegate()
let userAuthToken = UserDefaults.standard.string(forKey: "token")
let userKeyToken = UserDefaults.standard.string(forKey: "key")


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    // Disable dark mode
    if #available(iOS 13.0, *) {
        window?.overrideUserInterfaceStyle = .light
    }

    // IF USER IS LOGGED IN
    if let windowScene = (scene as? UIWindowScene) {

        if let _ = userAuthToken {
            self.window = UIWindow(windowScene: windowScene)

            // CREATE TAB BAR //
            let tabController = UITabBarController()

            tabController.tabBar.backgroundColor = .white

            // Instantiate the storyboards
            let cannabisStoryboard = UIStoryboard(name: "Cannabis", bundle: nil)
            let profileStoryboard = UIStoryboard(name: "Profile", bundle: nil)


            // Instantiate the view controllers to storyboards
            let cannabisVC = cannabisStoryboard.instantiateViewController(withIdentifier: "Cannabis") as! CannabisViewController
            let profileVC = profileStoryboard.instantiateViewController(withIdentifier: "Profile") as! ProfileViewController

            // Displays the items in below order in tab bar
            let vcData: [(UIViewController, UIImage, UIImage)] = [
                (cannabisVC, UIImage(named: "Cannabis_icon")!, UIImage(named: "Cannabis_icon_selected")!),
                (profileVC, UIImage(named: "Profile_icon")!, UIImage(named: "Profile_icon_selected")!),
            ]

            let vcs = vcData.map { (vc, defaultImage, selectedImage) -> UINavigationController in
                let nav = UINavigationController(rootViewController: vc)
                nav.tabBarItem.image = defaultImage
                nav.tabBarItem.selectedImage = selectedImage

                return nav
            }

            // Assign to tab bar controller
            tabController.viewControllers = vcs
            tabController.tabBar.isTranslucent = false
            tabController.delegate = tabBarDelegate

            // Disables rendering for tab bar images
            if let items = tabController.tabBar.items {
                for item in items {
                    if let image = item.image {
                        item.image = image.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                    }

                    if let selectedImage = item.selectedImage {
                        item.selectedImage = selectedImage.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                    }

                    // Hides title
                    item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
                }
            }

            // Customize Navigation bar
            UINavigationBar.appearance().backgroundColor = UIColor(rgb: 0x00ffcc)

            // Disable dark mode
            window!.overrideUserInterfaceStyle = .light

            window?.rootViewController = tabController
            window?.makeKeyAndVisible()



        } else {
            // let loginStoryboard = UIStoryboard(name: "Login", bundle: nil)
            // let loginViewController = loginStoryboard.instantiateViewController(withIdentifier: "Login") as! LoginViewController

            // Disable dark mode
            window!.overrideUserInterfaceStyle = .light

            // window?.rootViewController = loginViewController
            window?.rootViewController = LoginViewController()
            window?.makeKeyAndVisible()
        }



        window?.windowScene = windowScene
    }

}

Root ViewController(精简为相关信息)

class CannabisViewController: UIViewController {

// MARK:- Outlets
let tableView = UITableView()

// MARK:- Properties
var cannabisDetailViewController: CannabisDetailsViewController? = nil


// Search
let searchController = UISearchController(searchResultsController: nil)
var isSearchBarEmpty: Bool { return searchController.searchBar.text?.isEmpty ?? true }
var filteredStrains = [Cannabis]()
var isFiltering: Bool { return searchController.isActive && !isSearchBarEmpty }


// MARK: - ViewWillLayoutSubViews
override func viewWillLayoutSubviews() {
    let navigationBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 44))

    // navigationController?.setViewControllers([CannabisViewController()], animated: true)


    self.view.addSubview(navigationBar)
}

// MARK: - ViewDidLoad
override func viewDidLoad() {
    super.viewDidLoad()

    configurePage()


    // MARK: Self sizing table view cell
    tableView.estimatedRowHeight = CGFloat(88.0)
    tableView.rowHeight = UITableView.automaticDimension



    // MARK: DataSource/Delegate
    tableView.dataSource = self
    tableView.delegate = self


    // Removes default lines from table views
    tableView.tableFooterView = UIView()
    tableView.separatorStyle = .none


    // MARK: Navigation: logo in center
    let logoHeader = UIImageView(image: UIImage(named: "logoHeader"))
    self.navigationItem.titleView = logoHeader


    // MARK: API
    getCannabisList()


    // MARK: Search bar controller
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search for a strain!"
    navigationItem.searchController = searchController
    definesPresentationContext = true

}


// Configure TableView
func configurePage() {
    // Configure Tableview
    view.addSubview(tableView)
    tableView.anchor(top: view.topAnchor, left: view.leftAnchor,
                     bottom: view.bottomAnchor, right: view.rightAnchor)
}

}

SearchController(仍在根目录中ViewController)

    func updateSearchResults(for searchController: UISearchController) {
    let searchBar = searchController.searchBar
    let userSearch = searchBar.text!.trimmingCharacters(in: .whitespaces)
    search(searchText: userSearch)
}

我可以在这里看到几个问题,但首先要在 SceneDelegate 中初始化 window,您将使用 UIWindowScene:

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    self.window = window
    let rootViewController = RootViewController()
    window.rootViewController = UINavigationController(rootViewController: rootViewController)
    window.makeKeyAndVisible()
}

如果您想在您的应用中全局禁用深色模式,只需将键 UIUserInterfaceStyle 添加到您的 Info.plist 并将其值设置为 Dark(或 Light ).通过这样做,您将不需要更新每个视图控制器,因为它会覆盖全局应用程序默认样式。不过,我强烈建议您添加对深色模式的支持!

如果您想更改导航栏外观:

if #available(iOS 13.0, *) {
    let navigationAppearance = UINavigationBarAppearance()
    navigationAppearance.configureWithOpaqueBackground()
    navigationAppearance.backgroundColor = .white
    navigationAppearance.titleTextAttributes = // ...
    navigationAppearance.largeTitleTextAttributes = // ...
    UINavigationBar.appearance().tintColor = .systemBlue
    UINavigationBar.appearance().barTintColor = .white
    UINavigationBar.appearance().standardAppearance = navigationAppearance
    UINavigationBar.appearance().scrollEdgeAppearance = navigationAppearance
} else {
    UINavigationBar.appearance().backgroundColor = .white
    UINavigationBar.appearance().barTintColor = .white
    UINavigationBar.appearance().tintColor = .systemBlue
    UINavigationBar.appearance().titleTextAttributes = // ...
    UINavigationBar.appearance().largeTitleTextAttributes = // ...
}

我做了一个最小的项目让你看到一个搜索栏的工作示例,其中状态栏不会闪烁,UISearchBar 的 hide/show 动画当 pushing/popping 你的 DetailViewController:

时正常工作

RootViewController:

import UIKit

class RootViewController: UIViewController {

    private let reuseIdentifier = "reuseIdentifier"

    lazy var tableView: UITableView = {
        [=12=].delegate = self
        [=12=].dataSource = self
        [=12=].register(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
        return [=12=]
    }(UITableView(frame: .zero, style: .grouped))

    private lazy var searchController: UISearchController = {
        [=12=].searchResultsUpdater = self
        [=12=].delegate = self
        [=12=].searchBar.delegate = self
        [=12=].obscuresBackgroundDuringPresentation = false
        [=12=].hidesNavigationBarDuringPresentation = false
        [=12=].searchBar.backgroundColor = .white
        [=12=].searchBar.tintColor = .systemBlue
        return [=12=]
    }(UISearchController(searchResultsController: nil))

    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setupConstraints()
    }

    func setupViews() {
        title = "Source"
        view.backgroundColor = .white
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = false
        view.addSubview(tableView)
        // ...
    }

    func setupConstraints() {
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    }
}

extension RootViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let detailViewController = DetailViewController()
        navigationController?.pushViewController(detailViewController, animated: true)
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return nil
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return CGFloat.leastNonzeroMagnitude
    }
}

extension RootViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
        cell.textLabel?.text = "Cell at indexPath \(indexPath)"
        return cell
    }
}

extension RootViewController: UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {}
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {}
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {}
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {}
    func updateSearchResults(for searchController: UISearchController) {}
}

DetailViewController:

class DetailViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Detail"
        view.backgroundColor = .systemGray6
    }
}