文章目录
一、前言
iOS 界面开发最重要的首属ViewController
和View
,ViewController
是View
的控制器,也就是一般的页面,用来管理页面的生命周期(它相当于安卓里的Activity
,两者很像,但又有一些差异)。
ViewController
的特点是它有好几种。一种最基本的UIViewController
,和另外三种容器:UINavigationController
、UITabBarController
、UIPageViewController
。
所谓容器 ,就是它们本身不能单独用来显示,必须在里面放一个或几个UIViewController
。
不同容器有不同的页面管理方式和展示效果:
UINavigationController
用于导航栏管理页面;UITabBarController
用于底部tab管理页面;UIPageViewController
用于切换器管理页面;
容器还可以嵌套,比如把UITabBarController
放进UINavigationController
里面,这样在tab页面里,可以用启动导航栏样式的二级子页面。
二、UIViewController
这是最简单的页面,没有导航栏。
使用present
方法展示,展示时从底部弹起,可以用下滑手势关闭,也可以多次启动叠加多个页面。
代码实现如下:
objectivec
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
title = "\(self.hash)"
var label = UIButton(frame: CGRect(x: 10, y: 100, width: 300, height: 100))
label.setTitle("present ViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentVC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 200, width: 300, height: 100))
label.setTitle("present NavigationController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentNC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 300, width: 300, height: 100))
label.setTitle("push ViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(pushVC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 400, width: 300, height: 100))
label.setTitle("present TabbarController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentTC), for: .touchUpInside)
label = UIButton(frame: CGRect(x: 10, y: 500, width: 300, height: 100))
label.setTitle("present PageViewController", for: .normal)
view.addSubview(label)
label.addTarget(self, action: #selector(presentPC), for: .touchUpInside)
}
@objc func presentVC() {
let vc = ViewController()
vc.view.backgroundColor = .darkGray
present(vc, animated: true)
}
@objc func presentNC() {
let vc = ViewController()
vc.view.backgroundColor = .gray
let nc = UINavigationController(rootViewController: vc)
present(nc, animated: true)
}
@objc func presentTC() {
let tc = MyTabbarController()
tc.view.backgroundColor = .blue
let nc = UINavigationController(rootViewController: tc)
present(nc, animated: true)
}
@objc func presentPC() {
let pc = MyPageViewController()
pc.view.backgroundColor = .red
let nc = UINavigationController(rootViewController: pc)
present(nc, animated: true)
}
@objc func pushVC() {
let vc = ViewController()
vc.view.backgroundColor = .purple
if let nc = navigationController {
nc.pushViewController(vc, animated: true)
} else {
print("navigationController nil!")
}
}
}
三、UINavigationController
这是最常用的页面导航方式,顶部展示导航栏,有标题、返回按钮。
使用pushViewController
方法展示,展示时从右往左出现,可以用右滑手势关闭,也可以多次启动叠加多个页面。
注意⚠️:UINavigationController
用来管理一组UIViewController
,这些UIViewController
共用一个导航栏。
一般来说,UINavigationController
能很好地控制导航栏上面的元素显示和转场效果。
如果需要定制导航栏元素,尽量修改UIViewController
的导航栏,不要直接修改UINavigationController
的导航栏。
四、UITabBarController
这个一般用来做主页面的展示,下面配置多个tab,用于切换页面。
示例代码如下:
objectivec
class MyTabbarController: UITabBarController {
init() {
super.init(nibName: nil, bundle: nil)
self.tabBar.backgroundColor = .gray
let vc1 = ViewController()
vc1.tabBarItem.image = UIImage(named: "diamond")
vc1.tabBarItem.title = "tab1"
vc1.view.backgroundColor = .red
let vc2 = ViewController()
vc2.tabBarItem.image = UIImage(named: "diamond")
vc2.tabBarItem.title = "tab2"
vc2.view.backgroundColor = .blue
let vc3 = ViewController()
vc3.tabBarItem.image = UIImage(named: "diamond")
vc3.tabBarItem.title = "tab3"
vc3.view.backgroundColor = .purple
self.viewControllers = [
vc1,
vc2,
vc3,
]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
五、UIPageViewController
这个用来做翻页的页面,比如电子书或者广告banner。可以配置左右或上下翻译,翻页效果可以配置滚动或者模拟翻书。
用viewControllerBefore
和viewControllerAfter
回调方法控制页面切换。viewControllerBefore
方法提供当前页面的前一个页面,viewControllerAfter
方法提供当前页面的后一个页面。
注意⚠️:UIPageViewController
有预加载机制,它会提前加载当前页面的前后页面。但是没有实现页面缓存机制,需要在外部做缓存。
如果页面非常多,但又是同一个类的实例,那么一般创建三个实例就够了,然后在viewControllerBefore
和viewControllerAfter
方法里循环使用这三个。
示例代码如下:
objectivec
class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource {
lazy var vcs = [
ViewController(),
ViewController(),
ViewController(),
ViewController(),
ViewController(),
]
init() {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal)
self.dataSource = self
let vc1 = ViewController()
vc1.view.backgroundColor = .red
let vc2 = ViewController()
vc2.view.backgroundColor = .blue
let vc3 = ViewController()
vc3.view.backgroundColor = .purple
let vc4 = ViewController()
vc4.view.backgroundColor = .gray
vcs = [vc1,vc2,vc3,vc4
]
self.setViewControllers([vcs[0]], direction: .forward, animated: false)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let i = (vcs.firstIndex(of: viewController as! ViewController) ?? 0) - 1
if i < 0 {
return nil
}
return vcs[i]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let i = (vcs.firstIndex(of: viewController as! ViewController) ?? 0) + 1
if i >= vcs.count {
return nil
}
return vcs[i]
}
}