自定义 UITabBar
在一些需要使用 UITabBar 的项目中,目前大家的做法都是使用默认的样式。为了不显得那么丑,一般的做法也就更改一下选中的 item 的颜色,避免出现默认的蓝色的标题和图标。但是(不错,就是这个但是),如果当我点击 TabBar 中的某个 item 的时候,这个 item 的背景颜色应该要高亮。这样用户就会更加地容易知道当前点击的位置了(嗯,好像很有道理)。
如下图这个样子。
为了实现这个效果,我决定首先看看 UITabBar 有没有现成的方法。然而,并没有啊。既然 UITabBar 没有提供现成的方法,那么下一步的做法就是自定义一个 UITabBar 了。准备好了?GO!!!
开始前的准备
在自定义 UITabBar 之前需要把基本的架构做好。创建一个名为 TabBarViewController
的类,作为 window 的 rootViewController。接着再创建几个 UIViewController 的对象,对应到 UITabBar 的 item。
1 | override func viewDidLoad() { |
自定义 UITabBar
这里需要创建 2 个类,分别是 CustomTabBar
和 CustomTabBarItem
,都继承于 UIView
。它们的作用显而易见,CustomTabBar
用来“代替”系统的 UITabBar,而 CustomTabBarItem
则是 CustomTabBar
的 subView,作为 tabBar 上的元素。
CustomTabBar 的构成
CustomTabBar
在初始化的时候要配置好 CustomTabBarItem
对象,对其进行 addSubView 和 Frame 调整的操作。
整个类的代码如下:
1 | import UIKit |
还好代码不是很多。开始初始化的时候调用了 configTabBarItem()
方法,用来 addSubView CustomTabBarItem
对象。在 layoutSubviews()
方法中,调整 CustomTabBarItem
对象的 Frame。
CustomTabBarItem 的构成
CustomTabBarItem
的构成更为简单。主要是显示 title。
这个类的代码如下:
1 | import UIKit |
CustomTabBarItem
目前只加了一个 Label,用来显示标题。如果想要加上图片,过程跟添加 Label 差不多。
代码写到这里,基本上完成了自定义 UITabBar。剩下的就是在 TabBarViewController
中配置好 CustomTabBar
了。
使用 CustomTabBar
使用 CustomTabBar
的过程变得非常简单,只需要几行代码就可以看到效果了。
1 | var customTabBar = CustomTabBar() |
在 TabBarViewController
的 viewDidLoad()
方法中添加一下 2 行代码就可以了————还记得本文开头那里准备 TabBarViewController
的代码吗?没错,就是那个 viewDidLoad
。
1 | customTabBar.frame = tabBar.bounds |
最后,为了实现切换后高亮 item 的效果,需要实现一个 UITabBarDelegate
的代理方法。
1 | override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) { |
最后的步骤也完成了,看看效果如何。
是不是挺不错,哈哈。
存疑
UITabBarController
有一个 selectedIndex
的属性,起初我以为这个属性代表的是当前 item 的 index。然而,在 UITabBarDelegate
的 tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem)
方法中,print 出 selectedIndex
的值竟然是上一次点击 item 的 index。有趣的是,这个代理方法中,所点的 item 并不是 selectedIndex
对应的 item。这个是真・当前的 item。
目前的解决方法是利用这个代理方法中的 item 来获取其所在的 index,然后把这个 index 赋值给 selectedIndex
。
1 | let index: Int? = tabBar.items?.index(of: item) |
更新
正如前面所说的,在 UITabBarDelegate
的 tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem)
代理方法中,selectedIndex
并不是正确的 selectedIndex
。那么有没有另外的方法存在着正确的 selectedIndex
呢?
答案是当然有啦。这次的目光放到了 UITabBarControllerDelegate
这个代理。在 tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
的代理方法中 selectedIndex
是正确的。所以在这个方法里可以放心地赋值了。
1 | extension TabBarViewController: UITabBarControllerDelegate { |
哦,对了,不要忘记了设置代理。
1 | delegate = self |
总结
本文粗略地实现了自定义 UITabBar,当中还有比较多的不完善的地方。例如 TabBarViewController
所添加的 viewController 数量没有与 CustomTabBar
的 item 数量对接上。另外一个不那么完善的地方是更改 item 选中背景的方法可能并不是很好(使用 for 循环解决),即使不影响选中的效果。在整个过程中,核心方法就是利用 TabBarViewController
的 tabBar 属性(继承于 UIView)进行 addSubView。利用这一点,后面的步骤就比较简单了。