一、需求
1、一个tabbar控制器包含多个子控制器,这里以2个控制器为例FirstViewController(简称FVC)和SecondViewController(简称SVC)。FVC首页需要隐藏导航栏,push到子控制器显示导航栏同时还要隐藏底部tabbar条;2、点击SVC需要先present一个LoginViewController(简称LVC)判断登陆与否才能进入.
二、实现第一个需求隐藏导航栏
2.1 在FVC增加下面两个方法
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBar.isHidden = false
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isHidden = true
}
得到效果图:
感觉貌似都达到了我们的效果,可以如果你用手势返回的话,会发现顶部出现异常。
所以这种方法不可行。
2.2 进化版本
还是原来两个方法基础,修改代码如下:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: animated)
}
这样就达到我们要求了,Tip:在进入子控制器FirstChildViewController后,如果想让导航栏颜色和view颜色都为蓝色,没有界线就像隐藏了导航栏一样的效果:
你只需要自定义导航栏中添加如下两行代码:
bar.isTranslucent = false //取消导航栏透明效果
bar.shadowImage = UIImage()
三、实现第二个需求
在AppDelegate实现UITabBarControllerDelegate协议方法
//该方法在选择tabbaritem的时候调用
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController == tabBarController.viewControllers?.last {
let userIsLogin = UserDefaults.standard.bool(forKey: "userIsLogin")
if !userIsLogin {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginRegister = storyboard.instantiateViewController(withIdentifier: String(describing: LoginViewController.self)) as! LoginViewController
let nav = HWQNaviController(rootViewController: loginRegister)
self.tabbar.present(nav, animated: true, completion: nil)
}
return false
}
return true
// UserDefaults.standard.setValue(true, forKey: "presentLoginRegister")
}
效果如下:
功能实现,但发现一个bug,present时候,FVC顶部导航栏出现了;dismiss的时候FVC导航栏右消失了,看上去不协调。
问题出现之前在FVC中实现了viewWillDisappear、viewWillAppear方法,消失的时候导航栏会出现,出现的时候导航栏会隐藏。为解决这个问题可以添加一个常量(presentLoginRegister),判断它消失之前是push进入自己的子控制器还是present到另外的控制器中。代码如下:
//AppDelegate
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
........
//present到login时设置true
UserDefaults.standard.setValue(true, forKey: "presentLoginRegister")
self.tabbar.present(nav, animated: true, completion: nil)
}
return false
}
return true
}
//LoginViewController
override func viewDidLoad() {
super.viewDidLoad()
let left = UIBarButtonItem(image: UIImage(named: "关闭"), style: .plain, target: self, action: #selector(closeBtnTapped))
self.navigationItem.leftBarButtonItem = left
}
@objc func closeBtnTapped() {
let tabbar = UIApplication.shared.keyWindow?.rootViewController as! HWQTabbarController
tabbar.selectedIndex = 0
//UserDefaults.standard.setValue(false, forKey: PresentLoginRegister)
self.navigationController?.dismiss(animated: true, completion: nil)
}
//FVC
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let presentLoginRegister = UserDefaults.standard.bool(forKey: "presentLoginRegister")
if !presentLoginRegister {
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
}
presentLoginRegister的值为true表示要进入Login,为false则为进入子控制器或其它。
整个过程就解决了导航栏切换过程可能存在的bug。
github地址:https://github.com/hwqll/HWQCustomNavigation