iOS UITabBarController 嵌套 UINavigationController
本文處理兩個(gè)問(wèn)題:
1. 自定義導(dǎo)航按鈕后, 滑動(dòng)返回手勢(shì)失效問(wèn)題
2. TabBar 嵌套 NavigationBar 的 TabBar 顯示隱藏錯(cuò)亂等問(wèn)題
主要思路
- 使用 UITabBarController 作為 Window 的 rootViewController
- 自定義 UINavigationController 控制器, 全局控制 tabbar 的顯示與隱藏
- 添加自定義控制器為 UINavigationController 的 root 控制器
- UITabBarController 添加每個(gè) UINavigationController 控制器
直接上代碼
自定義的 UITabBarController :
import UIKit
class HomeTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
createChildController()
}
/// 通過(guò)自定義方法添加所有子控制器
func createChildController() {
addChildVC(childVc: HomeViewController(), title: "首頁(yè)", image: "IMG_Home", selectedImage: "IMG_Home_Selected")
addChildVC(childVc: MoreViewController(), title: "應(yīng)用", image: "IMG_More", selectedImage: "IMG_More_Selected")
addChildVC(childVc: MineViewController(), title: "我的", image: "IMG_Mine", selectedImage: "IMG_Mine_Selected")
}
/// 自定義添加子控制器
func addChildVC(childVc: UIViewController, title:String, image: String, selectedImage: String) {
let nav = HomeNavigationController(rootViewController: childVc)
let normalImage = UIImage(named: image)
let selectedImage = UIImage(named: selectedImage)
nav.navigationItem.title = title
nav.tabBarItem = tabbarItem(with: title, normalImage: normalImage!, selectedImage: selectedImage!)
addChildViewController(nav)
}
/// 快捷創(chuàng)建 UITabBarItem
func tabbarItem(with title: String, normalImage: UIImage, selectedImage: UIImage) -> UITabBarItem{
let image = normalImage.withRenderingMode(.alwaysOriginal)
let _selectedImage = selectedImage.withRenderingMode(.alwaysOriginal)
let tabBarItem = UITabBarItem(title: title, image: image, selectedImage: _selectedImage)
tabBarItem.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.mainColor], for: .selected)
tabBarItem.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.tabbarNormalColor], for: .normal)
return tabBarItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//讓圖片和文字在 iPad 下仍然保持上下排列
extension UITabBar {
override open var traitCollection: UITraitCollection {
if UIDevice.current.userInterfaceIdiom == .pad {
return UITraitCollection(horizontalSizeClass: .compact)
}
return super.traitCollection
}
}
自定義的 UINavigationController :
import UIKit
class HomeNavigationController: UINavigationController, UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
/// 自定義返回按鈕后返回手勢(shì)失效
/// 手動(dòng)實(shí)現(xiàn)返回手勢(shì)代理
interactivePopGestureRecognizer?.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
/// 如果當(dāng)前控制器的子控制器個(gè)數(shù)大于等于1, 說(shuō)明推出的控制器為子控制器
if childViewControllers.count > 0 {
/// 自定義返回按鈕
let backBtn = UIButton()
backBtn.setImage(UIImage(named: "IMG_Back"), for: .normal)
backBtn.addTarget(self, action: #selector(backButtonDidClick), for: .touchUpInside)
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBtn)
/// 子控制器隱藏 bottomBar
viewController.hidesBottomBarWhenPushed = true
}
super.pushViewController(viewController, animated: animated)
}
/// 返回按鈕點(diǎn)擊事件
@objc func backButtonDidClick() {
popViewController(animated: true)
}
/// 滑動(dòng)返回手勢(shì)
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
/// 判斷是否需要滑動(dòng)返回手勢(shì)
if gestureRecognizer == navigationController?.interactivePopGestureRecognizer {
return navigationController!.childViewControllers.count > 1
}
/// 解決當(dāng)前控制器為根控制器的時(shí)候, 返回手勢(shì)卡屏的問(wèn)題
if childViewControllers.count == 1 {
return false
}
return true
}
}