Antidote/Antidote/TabBarController.swift

164 lines
4.8 KiB
Swift

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
import UIKit
import SnapKit
private struct Constants {
static let HorizontalLineHeight = 0.5
}
class TabBarController: UITabBarController {
override var selectedIndex: Int {
didSet {
guard let navigation = viewControllers?[selectedIndex] as? UINavigationController else {
return
}
navigation.delegate = self
if oldValue == selectedIndex {
navigation.popToRootViewController(animated: true)
}
updateSelectedItems()
}
}
fileprivate let items: [TabBarAbstractItem]
fileprivate let theme: Theme
fileprivate var customTabBarView: UIView!
fileprivate var customTabBarViewVisibleConstraint: Constraint!
fileprivate var customTabBarViewHiddenConstraint: Constraint!
init(theme: Theme, controllers: [UINavigationController], tabBarItems: [TabBarAbstractItem]) {
self.theme = theme
self.items = tabBarItems
super.init(nibName: nil, bundle: nil)
viewControllers = controllers
delegate = self
}
required convenience init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
createCustomTabBarView()
addItems()
installConstraints()
updateSelectedItems()
}
}
extension TabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
guard let navigation = viewController as? UINavigationController else {
return
}
navigation.delegate = self
}
}
extension TabBarController: UINavigationControllerDelegate {
func navigationController(
_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
tabBar.isHidden = true
if viewController.hidesBottomBarWhenPushed {
customTabBarViewVisibleConstraint.deactivate()
customTabBarViewHiddenConstraint.activate()
}
else {
customTabBarViewHiddenConstraint.deactivate()
customTabBarViewVisibleConstraint.activate()
}
}
}
extension TabBarController {
func createCustomTabBarView() {
customTabBarView = UIView()
customTabBarView.backgroundColor = theme.colorForType(.NormalBackground)
view.addSubview(customTabBarView)
let horizontalLine = UIView()
horizontalLine.backgroundColor = theme.colorForType(.SeparatorsAndBorders)
customTabBarView.addSubview(horizontalLine)
horizontalLine.snp.makeConstraints {
$0.top.leading.trailing.equalTo(customTabBarView)
$0.height.equalTo(Constants.HorizontalLineHeight)
}
}
func addItems() {
for (index, item) in items.enumerated() {
item.didTapHandler = { [weak self] in
self?.selectedIndex = index
}
customTabBarView.addSubview(item)
}
}
func installConstraints() {
customTabBarView.snp.makeConstraints {
customTabBarViewVisibleConstraint = $0.bottom.equalTo(view.snp.bottom).constraint
customTabBarViewHiddenConstraint = $0.top.equalTo(view.snp.bottom).constraint
$0.leading.trailing.equalTo(view)
$0.height.equalTo(tabBar.frame.size.height)
// TODO: this moves the view a bit more to the top, because the home button "line" is in the way otherwise
// please fix me properly in the future
if #available(iOS 11.0, *) {
let keyWindow = UIApplication.shared.keyWindow
let b = keyWindow?.safeAreaInsets.bottom
customTabBarViewVisibleConstraint?.update(offset: -(b ?? 20))
}
}
customTabBarViewHiddenConstraint.deactivate()
var previous: TabBarAbstractItem?
for item in items {
item.snp.makeConstraints {
$0.top.bottom.equalTo(customTabBarView)
if previous != nil {
$0.leading.equalTo(previous!.snp.trailing)
$0.width.equalTo(previous!)
}
else {
$0.leading.equalTo(customTabBarView)
}
}
previous = item
}
previous!.snp.makeConstraints {
$0.trailing.equalTo(customTabBarView)
}
}
func updateSelectedItems() {
for (index, item) in items.enumerated() {
item.selected = (index == selectedIndex)
}
}
}