Swift:如何通过代码添加搜索栏至导航栏?子控制器复用HomeViewController搜索栏
Hey there! Let's break down your two questions about integrating a search bar with your navigation bar and accessing it from child view controllers—here's how to tackle them in Swift:
1. Adding a Search Bar to the Navigation Bar via Code
You have two common approaches here, depending on whether you want a basic search bar or the more modern, feature-rich UISearchController (recommended for iOS 11+):
Option 1: Basic UISearchBar Directly in Navigation Bar
This is straightforward if you just need a simple search bar without extra results handling:
import UIKit class HomeViewController: UIViewController, UISearchBarDelegate { override func viewDidLoad() { super.viewDidLoad() // Create and configure the search bar let searchBar = UISearchBar() searchBar.placeholder = "Search items..." searchBar.searchBarStyle = .minimal searchBar.tintColor = .systemBlue // Assign it to the navigation item's titleView navigationItem.titleView = searchBar // Set delegate to handle search events searchBar.delegate = self } // MARK: - UISearchBarDelegate func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { // Respond to search text changes here print("Current search query: \(searchText)") } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() // Hide keyboard when user taps search } }
Option 2: Using UISearchController (Modern Approach)
This gives you built-in features like a search results controller and better integration with the navigation bar:
import UIKit class HomeViewController: UIViewController, UISearchResultsUpdating { override func viewDidLoad() { super.viewDidLoad() let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.placeholder = "Search items..." searchController.obscuresBackgroundDuringPresentation = false // Keep content visible while searching // Attach to navigation bar navigationItem.searchController = searchController // Optional: Keep search bar visible even when scrolling navigationItem.hidesSearchBarWhenScrolling = false // Set updater to handle search text changes searchController.searchResultsUpdater = self } // MARK: - UISearchResultsUpdating func updateSearchResults(for searchController: UISearchController) { guard let searchText = searchController.searchBar.text else { return } // Handle search text updates here print("Search query updated: \(searchText)") } }
2. Accessing the HomeViewController's Search Bar from a Child View Controller
There are a few clean ways to do this, depending on how tightly coupled you want your view controllers to be:
Approach 1: Direct Parent Reference (Simple but Coupled)
If your child view controller is directly embedded in HomeViewController, you can cast the parent and access the search bar:
import UIKit class ChildViewController: UIViewController, UISearchBarDelegate { override func viewDidLoad() { super.viewDidLoad() // Get reference to HomeViewController guard let homeVC = parent as? HomeViewController else { print("Could not access HomeViewController") return } // Access search bar if using basic UISearchBar if let searchBar = homeVC.navigationItem.titleView as? UISearchBar { searchBar.delegate = self // Take over delegate if needed print("Current search text: \(searchBar.text ?? "")") } // Access search bar if using UISearchController if let searchController = homeVC.navigationItem.searchController { let searchBar = searchController.searchBar searchBar.placeholder = "Search from child VC" // Modify properties } } // MARK: - UISearchBarDelegate func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { // Handle search events in the child VC print("Child VC received search text: \(searchText)") } }
Approach 2: Closure/Delegate Pattern (Low Coupling, Recommended)
This avoids direct references and makes your code more reusable. Define a closure in HomeViewController to broadcast search events:
// In HomeViewController class HomeViewController: UIViewController, UISearchResultsUpdating { // Define a closure to pass search text changes var onSearchTextUpdated: ((String) -> Void)? override func viewDidLoad() { super.viewDidLoad() // ... setup search controller as before } func updateSearchResults(for searchController: UISearchController) { guard let searchText = searchController.searchBar.text else { return } onSearchTextUpdated?(searchText) // Broadcast the text change } } // In ChildViewController class ChildViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() guard let homeVC = parent as? HomeViewController else { return } // Subscribe to search text updates homeVC.onSearchTextUpdated = { [weak self] searchText in self?.updateChildContent(with: searchText) } } private func updateChildContent(with searchText: String) { // Update your child VC's UI/data based on the search text print("Updating child content with: \(searchText)") } }
Approach 3: NotificationCenter (For Cross-Controller Communication)
Use this if you need multiple view controllers to react to search changes, but it's less direct than the closure pattern:
// In HomeViewController func updateSearchResults(for searchController: UISearchController) { guard let searchText = searchController.searchBar.text else { return } // Post a notification with the search text NotificationCenter.default.post( name: NSNotification.Name("SearchTextUpdated"), object: nil, userInfo: ["searchText": searchText] ) } // In ChildViewController class ChildViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Listen for the notification NotificationCenter.default.addObserver( self, selector: #selector(handleSearchUpdate(_:)), name: NSNotification.Name("SearchTextUpdated"), object: nil ) } @objc private func handleSearchUpdate(_ notification: Notification) { if let searchText = notification.userInfo?["searchText"] as? String { updateChildContent(with: searchText) } } private func updateChildContent(with searchText: String) { // Update child VC content here } // Clean up observer when VC is deinitialized deinit { NotificationCenter.default.removeObserver(self) } }
内容的提问来源于stack exchange,提问作者podgradle

