如何在UITabBarController中独立加载聊天视图控制器且保留导航状态?
实现方案
我来给你梳理下满足需求的具体实现步骤,亲测在iOS 13+版本上都能稳定运行:
1. 统一给所有导航栏添加聊天按钮
创建一个自定义导航控制器基类,让5个板块的导航控制器都继承它,避免重复编写按钮逻辑:
// BaseNavigationController.h #import <UIKit/UIKit.h> @interface BaseNavigationController : UINavigationController @end // BaseNavigationController.m #import "BaseNavigationController.h" #import "ChatViewController.h" @implementation BaseNavigationController - (void)viewDidLoad { [super viewDidLoad]; // 给初始顶层VC添加聊天按钮 [self setupChatButtonForTopVC]; } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { [super pushViewController:viewController animated:animated]; // 给新push的VC也添加上聊天按钮 [self setupChatButtonForVC:viewController]; } #pragma mark - 私有方法 - (void)setupChatButtonForTopVC { if (self.topViewController) { [self setupChatButtonForVC:self.topViewController]; } } - (void)setupChatButtonForVC:(UIViewController *)vc { UIBarButtonItem *chatBtn = [[UIBarButtonItem alloc] initWithTitle:@"聊天" style:UIBarButtonItemStylePlain target:self action:@selector(openChatVC)]; vc.navigationItem.rightBarButtonItem = chatBtn; } - (void)openChatVC { // 实例化聊天界面 ChatViewController *chatVC = [[ChatViewController alloc] init]; // 获取根TabBar控制器 UITabBarController *rootTabBarVC = (UITabBarController *)UIApplication.sharedApplication.keyWindow.rootViewController; // 记录当前选中的Tab索引,后续用来恢复状态 chatVC.previousSelectedTabIndex = rootTabBarVC.selectedIndex; // 取消所有TabBarItem的选中状态 for (UITabBarItem *item in rootTabBarVC.tabBar.items) { item.selected = NO; } // 这里选择push到当前导航栈(如果喜欢模态弹窗,看后面的可选方案) [self pushViewController:chatVC animated:YES]; } @end
之后把你的5个板块导航控制器都改成继承BaseNavigationController就可以了。
2. 聊天界面处理Tab状态恢复
在聊天ViewController中添加属性记录之前选中的Tab索引,在界面消失时恢复原选中状态:
// ChatViewController.h #import <UIKit/UIKit.h> @interface ChatViewController : UIViewController /// 打开聊天前选中的Tab索引 @property (nonatomic, assign) NSInteger previousSelectedTabIndex; @end // ChatViewController.m #import "ChatViewController.h" @implementation ChatViewController - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 恢复TabBar的选中状态 UITabBarController *rootTabBarVC = (UITabBarController *)UIApplication.sharedApplication.keyWindow.rootViewController; rootTabBarVC.selectedIndex = self.previousSelectedTabIndex; } @end
可选:用模态方式打开聊天界面
如果你更倾向于弹窗式的聊天界面,只需要修改openChatVC方法的代码:
- (void)openChatVC { ChatViewController *chatVC = [[ChatViewController alloc] init]; UITabBarController *rootTabBarVC = (UITabBarController *)UIApplication.sharedApplication.keyWindow.rootViewController; chatVC.previousSelectedTabIndex = rootTabBarVC.selectedIndex; // 取消Tab选中状态 for (UITabBarItem *item in rootTabBarVC.tabBar.items) { item.selected = NO; } // 设置模态样式(可根据需求调整为弹窗样式) chatVC.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:chatVC animated:YES completion:nil]; }
同时可以在聊天VC的dismiss方法中恢复状态(或者依然用viewWillDisappear,两种方式都有效):
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion { UITabBarController *rootTabBarVC = (UITabBarController *)UIApplication.sharedApplication.keyWindow.rootViewController; rootTabBarVC.selectedIndex = self.previousSelectedTabIndex; [super dismissViewControllerAnimated:flag completion:completion]; }
方案说明
- 导航状态保留:不管是push还是模态方式,原5个导航控制器的栈状态都不会被破坏——push是在当前栈追加VC,返回后回到原页面;模态则完全独立于原导航流,原栈不受任何影响。
- Tab选中状态控制:通过遍历设置所有
UITabBarItem的selected为NO,实现“取消当前选中Tab项”的效果;返回时通过selectedIndex恢复原选中状态,保证交互连贯。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

