通常情况下,在实际开发过程中经常需要自定义UITabBarController,并且很有可能还涉及到自定义UITabBar和UIButton的情况。就以闲鱼为例,我们尝试着模仿一下它。
为了更好的演示和说明,整个演示项目都将使用纯代码来搭建。所以,来到AppDelegate文件中,实现以下代码:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// 创建窗口并设置其frame
window = UIWindow(frame: UIScreen.main.bounds)
// 设置窗口的背景颜色(便于调试)
window?.backgroundColor = .white
// 设置窗口的根控制器
window?.rootViewController = MainViewController()
// 显示窗口
window?.makeKeyAndVisible()
return true
}
因为我们的主要目的是演示自定义相关控件,所以在项目搭建的过程中会省略一些细节,不过,我会尽可能的保证逻辑清晰和完整。上述代码完成之后,运行程序就可以看到下面有一个TabBar了:
来到MainViewController这个文件中添加子控制器。MainViewController是我们自己新建的文件,它继承自UITabBarController。通常情况下,为了保证代码逻辑的清晰,同时也便于后续的阅读和维护,我们都会将具有某种功能的代码抽取到一个方法中,我们这里也采用这种方式:
class MainViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// 统一设置UI界面
setupUI()
}
}
// MARK: - 设置UI界面
extension MainViewController {
/// 统一设置UI界面
fileprivate func setupUI() {
// 一次性添加所有的子控制器
addChildViewControllers()
}
/// 一次性添加所有的子控制器
private func addChildViewControllers() {
// 分别添加各子控制器
addChildViewController(HomeViewController(), title: "首页", imageName: "home")
addChildViewController(FishpondViewController(), title: "鱼塘", imageName: "fishpond")
// addChildViewController(UIViewController()) // 占位控制器
addChildViewController(MessageViewController(), title: "消息", imageName: "message")
addChildViewController(AccountViewController(), title: "我的", imageName: "account")
}
/// 添加单个子控制器
private func addChildViewController(_ childController: UIViewController, title: String, imageName: String) {
// 设置子控制器的标题
childController.title = title
// 设置子控制器tabBarItem的图片
childController.tabBarItem.image = UIImage(named: imageName + "_normal")
childController.tabBarItem.selectedImage = UIImage(named: imageName + "_highlight")
// 将子控制器包装成导航控制器
let nav = UINavigationController(rootViewController: childController)
// 将导航控制器添加到父控制器中
addChildViewController(nav)
}
}
想必你可能注意到了,在添加子控制器的过程中,我们有一行代码(设置占位控制器的那一行)注释掉了。其实这也是一种思路,就是碰到tabBar中间有一个特殊按钮时,我们可以先搞一个占位控制器,然后在这个占位控制器的tabBarItem上覆盖一个按钮以实现我们的目的,这种方式的好处是省事,不好的地方是浪费性能。虽然总体影响几乎可以忽略不计,但毕竟还有一个闲置的控制器呢!所以,我们这里不用这种方式。我们采用的方式是,重新调整其它tabBarItem的位置,然后在正中间添