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
}
}
我正在努力以编程方式重建我的应用程序,而不是使用情节提要和 运行 解决我的 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
}
}