iOS旧版本中大标题导航栏实现咨询:替代prefersLargeTitles方案
Got it, let's tackle this problem for iOS versions below 11.0. Since the native prefersLargeTitles isn't available there, we have two solid approaches to achieve a similar large navigation bar effect or just increase the navigation bar height without blocking your content:
This method replicates the iOS 11+ large title look by adding a custom title view, since the system doesn't support it natively pre-iOS 11.
Step 1: Hide the Default System Title
First, replace the default title with an empty placeholder to free up space:
override func viewDidLoad() { super.viewDidLoad() // Hide the default title navigationItem.titleView = UIView() }
Step 2: Add a Custom Large Title Label
Create a bold, large font label and attach it to the navigation bar. We'll use auto layout to ensure it fits across devices:
override func viewDidLoad() { super.viewDidLoad() navigationItem.titleView = UIView() let largeTitleLabel = UILabel() largeTitleLabel.text = "Your Large Title" largeTitleLabel.font = UIFont.systemFont(ofSize: 34, weight: .bold) largeTitleLabel.textColor = .label // Use .black if targeting iOS < 13 largeTitleLabel.translatesAutoresizingMaskIntoConstraints = false // Add the label to the navigation bar navigationController?.navigationBar.addSubview(largeTitleLabel) // Set up constraints to align it properly NSLayoutConstraint.activate([ largeTitleLabel.leadingAnchor.constraint(equalTo: navigationController!.navigationBar.leadingAnchor, constant: 16), largeTitleLabel.bottomAnchor.constraint(equalTo: navigationController!.navigationBar.bottomAnchor, constant: -8), largeTitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: navigationController!.navigationBar.trailingAnchor, constant: -16) ]) }
Optional: Add Scroll-Driven Animation (Like iOS 11+)
If you want the title to shrink and move up when scrolling (just like the native large title), listen to your scroll view's scrollViewDidScroll method:
extension YourViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { guard let navBar = navigationController?.navigationBar, let largeTitleLabel = navBar.subviews.first(where: { $0 is UILabel }) as? UILabel else { return } let scrollOffset = scrollView.contentOffset.y // Adjust the scale and position based on scroll offset let scale = max(0.7, 1 - (scrollOffset / 60)) // 60 is the threshold for full shrink let yOffset = min(0, -scrollOffset / 3) largeTitleLabel.transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: 0, y: yOffset) } }
If you don't need the large title look and just want a taller navigation bar to fit custom content, here are two ways to do it:
Option A: Custom Navigation Bar Subclass
Create a custom navigation bar that overrides the default size:
class TallNavigationBar: UINavigationBar { override func sizeThatFits(_ size: CGSize) -> CGSize { // Set your desired height (default is 44; 88 gives a large, tall bar) return CGSize(width: UIScreen.main.bounds.width, height: 88) } }
Then use this custom bar when initializing your navigation controller:
let navController = UINavigationController(navigationBarClass: TallNavigationBar.self, toolbarClass: nil) navController.viewControllers = [YourViewController()]
Option B: Add an Extended Bar Below the Navigation Bar
If you don't want to subclass the navigation bar, add a separate view below it to extend the height:
override func viewDidLoad() { super.viewDidLoad() let extendedBar = UIView() extendedBar.backgroundColor = navigationController?.navigationBar.backgroundColor ?? .white extendedBar.translatesAutoresizingMaskIntoConstraints = false view.addSubview(extendedBar) // Pin the extended bar to the bottom of the navigation bar NSLayoutConstraint.activate([ extendedBar.topAnchor.constraint(equalTo: navigationController!.navigationBar.bottomAnchor), extendedBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), extendedBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), extendedBar.heightAnchor.constraint(equalToConstant: 44) // Adjust height as needed ]) // Adjust your scroll view's content inset to avoid content being blocked if #available(iOS 11.0, *) { tableView.contentInsetAdjustmentBehavior = .never let totalBarHeight = (navigationController?.navigationBar.frame.height ?? 44) + extendedBar.frame.height tableView.contentInset = UIEdgeInsets(top: totalBarHeight, left: 0, bottom: 0, right: 0) } else { // Pre-iOS 11 needs to account for the status bar height (20pt) let totalBarHeight = (navigationController?.navigationBar.frame.height ?? 44) + extendedBar.frame.height + 20 tableView.contentInset = UIEdgeInsets(top: totalBarHeight, left: 0, bottom: 0, right: 0) } tableView.scrollIndicatorInsets = tableView.contentInset }
Key Notes for Both Approaches
- Status Bar Adaptation: Make sure to set the correct status bar style (light/dark) to match your custom bar's background color.
- Layout Consistency: Test on different device sizes (especially iPhone SE and larger models) to ensure your custom views don't overflow or misalign.
- Interaction: If adding custom buttons to the tall bar, make sure their tap targets are accessible and don't overlap with other elements.
内容的提问来源于stack exchange,提问作者Faheem Rahman

