如何将UINavigationItem的titleView设为UIViewController视图且不加入导航栈?
核心思路
避免将标题用的控制器设为任何导航控制器或当前顶部控制器的子控制器,通过强引用控制器保证其生命周期,并手动管理必要的生命周期方法,直接将其视图设置为navigationItem.titleView。
具体实现步骤
- 创建自定义标题控制器:实现你需要的标题布局和业务逻辑。
- 强引用控制器:在当前顶部视图控制器中持有该标题控制器的强引用,防止其被提前释放。
- 手动初始化视图:调用
loadViewIfNeeded()确保视图被加载完成,再赋值给titleView。 - 手动管理生命周期:根据需求调用标题控制器的生命周期方法(如
viewWillAppear、viewWillDisappear),保证内部逻辑正常触发。
代码示例
Swift 版本
// 自定义标题控制器 class CustomTitleVC: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .clear let titleLabel = UILabel() titleLabel.text = "自定义标题" titleLabel.textColor = .black titleLabel.font = .systemFont(ofSize: 18, weight: .bold) view.addSubview(titleLabel) titleLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } } // 当前顶部视图控制器 class TopViewController: UIViewController { // 强引用标题控制器,避免被ARC释放 private var customTitleVC: CustomTitleVC! override func viewDidLoad() { super.viewDidLoad() setupCustomTitleView() } private func setupCustomTitleView() { customTitleVC = CustomTitleVC() // 手动加载视图 customTitleVC.loadViewIfNeeded() // 触发视图即将显示的逻辑 customTitleVC.viewWillAppear(true) // 设置为导航栏标题视图 navigationItem.titleView = customTitleVC.view } // 同步布局变化,保证标题视图适配屏幕旋转等场景 override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() customTitleVC.viewWillLayoutSubviews() } deinit { // 触发视图消失的收尾逻辑 customTitleVC.viewDidDisappear(true) } }
Objective-C 版本
// 自定义标题控制器 @interface CustomTitleVC : UIViewController @end @implementation CustomTitleVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor clearColor]; UILabel *titleLabel = [[UILabel alloc] init]; titleLabel.text = @"自定义标题"; titleLabel.textColor = [UIColor blackColor]; titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; [self.view addSubview:titleLabel]; titleLabel.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [titleLabel.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], [titleLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] ]]; } @end // 当前顶部视图控制器 @interface TopViewController () @property (nonatomic, strong) CustomTitleVC *customTitleVC; @end @implementation TopViewController - (void)viewDidLoad { [super viewDidLoad]; [self setupCustomTitleView]; } - (void)setupCustomTitleView { self.customTitleVC = [[CustomTitleVC alloc] init]; // 手动加载视图 [self.customTitleVC loadViewIfNeeded]; // 触发视图即将显示的逻辑 [self.customTitleVC viewWillAppear:YES]; // 设置为导航栏标题视图 self.navigationItem.titleView = self.customTitleVC.view; } // 同步布局变化,保证标题视图适配屏幕旋转等场景 - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; [self.customTitleVC viewWillLayoutSubviews]; } - (void)dealloc { // 触发视图消失的收尾逻辑 [self.customTitleVC viewDidDisappear:YES]; } @end
关键注意事项
- 强引用不可省略:如果不持有标题控制器的强引用,控制器会被ARC自动释放,导致视图变成野指针引发崩溃。
- 生命周期按需调用:若标题控制器包含数据请求、动画等依赖生命周期的逻辑,需手动调用对应方法保证逻辑正常执行。
- 布局同步要及时:在顶部控制器的
viewWillLayoutSubviews中调用标题控制器的对应方法,确保标题视图在屏幕旋转、尺寸变化时布局正确。
内容的提问来源于stack exchange,提问作者Michael Berk
相关产品推荐
相关产品推荐

