You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift如何在UIViewController中创建适配的UINavigationController

问题背景
  • 技术栈:Swift + Storyboard 开发iOS多场景应用,需求是为所有视图控制器配置UINavigationController,代码实现、Storyboard可视化实现两种方案均可。
  • 此前尝试手动创建UINavigationBar实现导航效果,存在两个问题:
    1. 固定frame布局无法适配所有尺寸的iPhone机型
    2. 导航栏上的按钮无法响应点击事件
  • 原有错误实现代码如下:
override func viewDidLoad() {
    super.viewDidLoad()
    let height: CGFloat = 50
    let width = self.view.frame.width
    let navbar = UINavigationBar(frame: CGRect(x: 0, y: 40, width: width, height: height))
    navbar.backgroundColor = UIColor.white
    navbar.delegate = self

    let navItem = UINavigationItem()
    navItem.title = "Last Call"
    navItem.rightBarButtonItem = UIBarButtonItem(title: "Add New", style: .plain, target: self, action: nil)

    navbar.items = [navItem]

    view.addSubview(navbar)

    self.view.frame = CGRect(x: 0, y: height, width: width, height: (UIScreen.main.bounds.height - height))
}
  • 另外尝试过直接给视图控制器嵌入Navigation Controller,最终展示效果不符合预期。
问题根因
  • 手动添加UINavigationBar的实现违反UIKit设计规范:硬编码y轴偏移40pt、导航栏高度50pt,没有考虑刘海/灵动岛机型的安全区规则、不同设备的屏幕尺寸差异,同时强行修改当前控制器view的frame会破坏系统默认的布局适配逻辑,必然出现错位。
  • 导航按钮无响应的直接原因:创建UIBarButtonItem时action参数传入nil,没有绑定实际的响应方法,点击事件无法触发。
  • 直接嵌入导航控制器效果异常,一般是嵌入流程错误,没有将导航控制器设置为对应场景的入口根控制器,或者自定义导航栏属性时破坏了系统默认布局。
正确实现方案

方案1:Storyboard可视化实现(推荐)

  1. 打开Storyboard文件,选中需要配置导航栏的目标视图控制器。
  2. 点击Xcode顶部菜单栏路径:Editor -> Embed In -> Navigation Controller,系统会自动创建UINavigationController实例,将当前选中的控制器设置为导航控制器的根视图,自动完成安全区适配、导航栏默认布局逻辑。
  3. 多场景应用不需要给每个子页面重复嵌入导航控制器,只需要给每个独立入口场景(比如TabBar的每个分页、模态跳转的根页面)执行上述嵌入操作即可,后续push的子页面会自动复用当前导航栈的导航栏。
  4. 导航栏内容直接在对应控制器内通过navigationItem配置即可,不需要手动创建UINavigationBar实例。

方案2:纯代码实现

不要手动将UINavigationBar作为子视图添加到控制器view上,正确做法是将目标控制器包装为UINavigationController的根控制器,在页面入口处完成导航控制器初始化:

// 入口处初始化示例(可在SceneDelegate、AppDelegate,或者跳转触发逻辑中编写)
let targetVC = YourCustomViewController()
let navController = UINavigationController(rootViewController: targetVC)
// 作为窗口根控制器使用
window?.rootViewController = navController
// 作为模态跳转页面使用
// present(navController, animated: true)

在目标控制器内部配置导航栏内容时,不要硬编码布局参数,通过系统提供的接口配置即可,同时给按钮绑定实际的响应方法:

override func viewDidLoad() {
    super.viewDidLoad()
    // 配置导航栏标题
    navigationItem.title = "Last Call"
    // 配置右侧按钮,必须绑定对应action方法,不能传nil
    navigationItem.rightBarButtonItem = UIBarButtonItem(
        title: "Add New",
        style: .plain,
        target: self,
        action: #selector(addNewAction)
    )
}

// 实现按钮点击响应方法
@objc private func addNewAction() {
    // 编写新增按钮的业务逻辑
}

核心注意点:不要硬编码导航栏的高度、y轴起始坐标,UIKit会自动根据设备状态栏高度、安全区域规则调整导航栏的位置和尺寸,手动写死frame必然出现多机型适配问题。

内容的提问来源于stack exchange,提问作者Mariglen Meta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:34:12