iOS Swift5从0到1系列(二):学习UITabBarController

一、前言

没想到本系列第一篇开局就能收获这么多朋友的喜爱与鼓励,让我更有动力继续本系列。

之所有出的这么慢,也是因为,我希望尽量把每个知识点讲到位,哪怕你是零基础,致力想成员一名 iOSer 的朋友,也能够再学习本系列的时候,掌握知识细节,所以,每遇到我认为是一个需要展开分析的点的内容,我都会反复再三确认,并认真思考如何用最好的方式来呈现给大家。

既然要做本系列,我们肯定要选择一个模仿的『对象』,而这个『对象』,如果大家之前有看过我分享的《抓包工具 Charles》,大家一定可以猜的出来,我们本系列将要模仿的『对象』是:\color{red}{京东APP}

今天先仿京东APP的底部导航栏,如下图:

jdapp-tabbar.png

二、底部导航栏控制器(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 的使用

按照上一篇的内容,我们先创建工程,一切就绪如下:

ready.png

3.1、创建 MainTabBarController

先创建一个『New Group』,然后『New File』,如下:

MainTabBarController.png

选择『Cocoa Touch Class』,Subclass of 选择 UITabBarController:

SubClassOf.png

3.2、添加 Group 及 5个 UIViewController

5-vcs.png

3.3、修改 AppDelegate.swift

我们修改 AppDelegate.swift,让 window 的 rootViewController 为我们的 MainTabBarController:

modify-app-delegate.png

运行模拟器如下显示:

tabbar-run.png

最底部灰色区域就是底部导航 UITabBar。

3.4、添加 icons

因为现在 macOS App Store 已经不允许下载 app 包到电脑,因此只能去官网下载 Android APK包,zip 解压后,搜索『.png』文件,结果只发现了『分类』、『购物车』和『我的』三种图标,而『首页』和『发现』没有找到。往年,双11 京东 app 底部的 icons 都会变,所以,底部图标默认的应该不是我们现在看到的样子,但总之,不影响我们的 demo 学习。

从 android apk 中拿到资源后,观察尺寸大小,将 40x40 的命名为 @2x,而 60x60 的命名为 @3x,如下:

images.png

然后选择 Xcode 项目中的『Assets.xcassets』,将上面的图标拖进去即可:

drag-image.png

释放后,Xcode 会自动识别,如下:

after-drag.png

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

截图如下:

src-all.png

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

3.7、运行模拟器

run-home.png
run-category.png

好了,本篇分享就到此结束,如果大家有什么问题,也希望多交流,谢谢!源代码会在下几次分享后,整体上传!后续会再次编辑此文,也可继续关注,谢谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容