iOS开发进阶(十一):ViewController 控制器详解

文章目录

一、前言

iOS 界面开发最重要的首属ViewControllerViewViewControllerView的控制器,也就是一般的页面,用来管理页面的生命周期(它相当于安卓里的Activity,两者很像,但又有一些差异)。

ViewController的特点是它有好几种。一种最基本的UIViewController,和另外三种容器:UINavigationControllerUITabBarControllerUIPageViewController

所谓容器 ,就是它们本身不能单独用来显示,必须在里面放一个或几个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。可以配置左右或上下翻译,翻页效果可以配置滚动或者模拟翻书。

viewControllerBeforeviewControllerAfter回调方法控制页面切换。viewControllerBefore方法提供当前页面的前一个页面,viewControllerAfter方法提供当前页面的后一个页面。

注意⚠️:UIPageViewController有预加载机制,它会提前加载当前页面的前后页面。但是没有实现页面缓存机制,需要在外部做缓存。

如果页面非常多,但又是同一个类的实例,那么一般创建三个实例就够了,然后在viewControllerBeforeviewControllerAfter方法里循环使用这三个。

示例代码如下:

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]
    }
}

六、拓展阅读

相关推荐
SoraLuna2 小时前
「Mac玩转仓颉内测版10」PTA刷题篇1 - L1-001 Hello World
算法·macos·cangjie
iFlyCai2 小时前
Xcode 16 pod init失败的解决方案
ios·xcode·swift
_可乐无糖7 小时前
mac终端使用pytest执行iOS UI自动化测试方法
macos·pytest
后端常规开发人员10 小时前
在 Mac 上使用 Docker 安装宝塔并部署 LNMP 环境
macos·docker·容器·宝塔
郝晨妤11 小时前
HarmonyOS和OpenHarmony区别是什么?鸿蒙和安卓IOS的区别是什么?
android·ios·harmonyos·鸿蒙
Hgc5588866611 小时前
iOS 18.1,未公开的新功能
ios
nukix12 小时前
Mac Java 使用 tesseract 进行 ORC 识别
java·开发语言·macos·orc
CocoaKier13 小时前
苹果商店下载链接如何获取
ios·apple
SoraLuna13 小时前
「Mac玩转仓颉内测版7」入门篇7 - Cangjie控制结构(下)
算法·macos·动态规划·cangjie
Algorithm157615 小时前
mac上使用docker搭建gitlab
macos·docker·gitlab