iOS Swift5从0到1系列(二):学习UITabBarCo
一、前言
既然要做本系列,我们肯定要选择一个模仿的『对象』,而这个将要模仿的『对象』是:
今天先仿京东APP的底部导航栏,如下图:
二、底部导航栏控制器(UITabBarController)
我们打开京东APP,进入到它的主页,就能看到最底部有一排五个按钮,每个按钮都对应着一个页面(我们称之为 ViewController),因此,最底部我们称之为『底部导航栏』。
源码注释:
If more than five view controllers are added to a tab bar controller, only the first four will display.
如果创建的个数大于5个,将会直接显示前4个。
The rest will be accessible under an automatically generated More item.
剩下的将会都收敛到一个叫作『更多』的按钮中。
这也就是为何几乎绝大多数 APP 都只定义不超过 5 个按钮及对应的 ViewController 的原因;源码注释中,并没有说最少定义几个,不过,一般来说至少定义 2 个以上(如果定义为一个,虽然可以,但那使用 UITabBarController 就没有任何意义)。
在正式开始学习使用前,我们先分析下 UIKit.UITabBarController 中的源码。
2.1、UITabBarController 分析
@available(iOS 2.0, *)
open class UITabBarController : UIViewController, UITabBarDelegate, NSCoding {
open var viewControllers: [UIViewController]?
......
}
我们看到:
- UITabBarController 继承于 UIViewController;
- 实现了 UITabBarDelegate 即 UITabBar(底部按钮的委托);
- 以及 NSCoding(归档与反归档数据存取协议);
- 定义了 UIViewController 对象可 nil 数组;
2.2、扩展 UIViewController 分析
extension UIViewController {
// Automatically created lazily with the view controller's title if it's not set explicitly.
open var tabBarItem: UITabBarItem!
// If the view controller has a tab bar controller as its ancestor, return it. Returns nil otherwise.
open var tabBarController: UITabBarController? { get }
}
如上源码,对 UIViewController 进行了扩展,内置了 UITabBar 的按钮,即 tabBarItem,该按钮可以添加文件、图标、消息汽泡等。
三、UITabBarController 的使用
按照上一篇的内容,我们先创建工程,一切就绪如下:
3.1、创建 MainTabBarController
先创建一个『New Group』,然后『New File』,如下:
选择『Cocoa Touch Class』,Subclass of 选择 UITabBarController:
3.2、添加 Group 及 5个 UIViewController
3.3、修改 AppDelegate.swift
我们修改 AppDelegate.swift,让 window 的 rootViewController 为我们的 MainTabBarController:
运行模拟器如下显示:
最底部灰色区域就是底部导航 UITabBar。
3.4、添加 icons
因为现在 macOS App Store 已经不允许下载 app 包到电脑,因此只能去官网下载 Android APK包,zip 解压后,搜索『.png』文件,结果只发现了『分类』、『购物车』和『我的』三种图标,而『首页』和『发现』没有找到。往年,双11 京东 app 底部的 icons 都会变,所以,底部图标默认的应该不是我们现在看到的样子,但总之,不影响我们的 demo 学习。
从 android apk 中拿到资源后,观察尺寸大小,将 40x40 的命名为 @2x,而 60x60 的命名为 @3x,如下:
然后选择 Xcode 项目中的『Assets.xcassets』,将上面的图标拖进去即可:
释放后,Xcode 会自动识别,如下:
3.5、实现 UITabBarController 功能
代码如下(以下代码是经过反复优化过后的):
//
// MainTabBarController.swift
// JDApp
//
// Created by qingye on 2021/3/5.
//
import UIKit
class MainTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
initTabBar()
}
func initTabBar() {
let home = HomeViewController()
home.tabBarItem.title = "首页"
let category = CategoryViewController()
category.tabBarItem.title = "分类"
category.tabBarItem.image = UIImage(named: "category.png")
let found = FoundViewController()
found.tabBarItem.title = "发现"
let cart = CartViewController()
cart.tabBarItem.title = "购物车"
cart.tabBarItem.image = UIImage(named: "cart.png")
let mine = MineViewController()
mine.tabBarItem.title = "我的"
mine.tabBarItem.image = UIImage(named: "mine.png")
viewControllers = [home, category, found, cart, mine]
// 设置 tabBar & tabBarItem
setTabBarItemAttributes(bgColor: UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1))
}
/// 这种方式比较灵活
func setTabBarItemAttributes(fontName: String = "Courier",
fontSize: CGFloat = 14,
normalColor: UIColor = .gray,
selectedColor: UIColor = .red,
bgColor: UIColor = .white) {
// tabBarItem 文字大小
var attributes: [NSAttributedString.Key: Any] = [.font: UIFont(name: fontName, size: fontSize)!]
// tabBarItem 文字默认颜色
attributes[.foregroundColor] = normalColor
UITabBarItem.appearance().setTitleTextAttributes(attributes, for: .normal)
// tabBarItem 文字选中颜色
attributes[.foregroundColor] = selectedColor
UITabBarItem.appearance().setTitleTextAttributes(attributes, for: .selected)
// tabBar 文字、图片 统一选中高亮色
tabBar.tintColor = selectedColor
// tabBar 背景色
tabBar.barTintColor = bgColor
}
}
截图如下:
3.7、运行模拟器
3.6、修改 HomeViewController 及 CategoryViewController
- HomeViewController
//
// HomeViewController.swift
// JDApp
//
// Created by qingye on 2021/3/6.
//
import UIKit
class HomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
let label = UILabel(frame: CGRect.zero)
label.text = "HomeViewController"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
- CategoryViewController
//
// CategoryViewController.swift
// JDApp
//
// Created by qingye on 2021/3/6.
//
import UIKit
class CategoryViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect.zero)
label.text = "CategoryViewController"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}