Created
October 29, 2019 11:59
-
-
Save churabou/29e59e02a93f3640b5d3e47890042609 to your computer and use it in GitHub Desktop.
Custom TabBarViewController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
extension UIColor { | |
convenience init(hex: UInt32, alpha: CGFloat = 1) { | |
let r = CGFloat((hex & 0xFF0000) >> 16) / 255 | |
let g = CGFloat((hex & 0x00FF00) >> 8) / 255 | |
let b = CGFloat(hex & 0x0000FF) / 255 | |
self.init(red: r, green: g, blue: b, alpha: alpha) | |
} | |
} | |
final class DummyViewController: UIViewController { | |
private var text: String | |
private var color: UIColor | |
init(text: String, color: UIColor) { | |
self.text = text | |
self.color = color | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func loadView() { | |
let label = UILabel() | |
label.text = text | |
label.backgroundColor = color | |
label.font = .boldSystemFont(ofSize: 40) | |
label.textColor = .white | |
label.textAlignment = .center | |
view = label | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
print(#function, text) | |
} | |
override func viewWillAppear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
print(#function, text) | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
print(#function, text) | |
} | |
override func viewWillDisappear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
print(#function, text) | |
} | |
override func viewDidDisappear(_ animated: Bool) { | |
super.viewDidDisappear(animated) | |
print(#function, text) | |
} | |
} | |
protocol TabViewDelegate: AnyObject { | |
func didSelectTab(_ selectedIndex: Int) | |
} | |
final class TabView: UIView { | |
weak var delegate: TabViewDelegate? | |
private var buttons: [UIButton] = [] | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
initializeView() | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
let width = bounds.width / CGFloat(buttons.count) | |
let height = bounds.height | |
buttons.enumerated().forEach { index, button in | |
button.frame = CGRect( | |
origin: CGPoint(x: width * CGFloat(index), y: 0), | |
size: CGSize(width: width, height: height) | |
) | |
} | |
} | |
} | |
private extension TabView { | |
func initializeView() { | |
buttons = (0...3).map { index in | |
let button = UIButton() | |
button.tag = index | |
button.setTitle(index.description, for: .normal) | |
button.titleLabel?.font = .boldSystemFont(ofSize: 28) | |
button.setTitleColor(.white, for: .normal) | |
button.backgroundColor = .black | |
button.addTarget(self, action: #selector(selectButton), for: .touchUpInside) | |
addSubview(button ) | |
return button | |
} | |
} | |
@objc func selectButton(_ sender: UIButton) { | |
delegate?.didSelectTab(sender.tag) | |
} | |
} | |
final class TabViewController: UIViewController { | |
private let contentView = UIView() | |
private let tabView = TabView() | |
private let viewControllers = [ | |
DummyViewController(text: "0", color: UIColor(hex: 0xffc4e4)), | |
DummyViewController(text: "1", color: UIColor(hex: 0xc4f4ff)), | |
DummyViewController(text: "2", color: UIColor(hex: 0xcfffd9)), | |
DummyViewController(text: "3", color: UIColor(hex: 0xddd1ff)) | |
] | |
private var selectedViewController: UIViewController? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.addSubview(contentView) | |
tabView.delegate = self | |
view.addSubview(tabView) | |
if let firstViewController = viewControllers.first { | |
selectedViewController = firstViewController | |
add(controller: firstViewController) | |
} | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
let tabviewHeight: CGFloat = 80 | |
contentView.frame = CGRect( | |
origin: .zero, | |
size: CGSize(width: view.bounds.width, height: view.bounds.height - tabviewHeight) | |
) | |
tabView.frame = CGRect( | |
origin: CGPoint(x: 0, y: contentView.bounds.height), | |
size: CGSize(width: view.bounds.width, height: tabviewHeight) | |
) | |
} | |
} | |
extension TabViewController: TabViewDelegate { | |
func didSelectTab(_ selectedIndex: Int) { | |
guard let fromViewController = selectedViewController, | |
viewControllers.count > selectedIndex else { | |
return | |
} | |
let toViewController = viewControllers[selectedIndex] | |
if fromViewController !== toViewController { | |
toViewController.beginAppearanceTransition(true, animated: true) | |
fromViewController.beginAppearanceTransition(false, animated: true) | |
add(controller: toViewController) | |
remove(controller: fromViewController) | |
fromViewController.endAppearanceTransition() | |
toViewController.endAppearanceTransition() | |
selectedViewController = toViewController | |
} | |
} | |
} | |
private extension TabViewController { | |
func add(controller: UIViewController) { | |
controller.willMove(toParent: self) | |
addChild(controller) | |
controller.view.frame = view.bounds | |
contentView.addSubview(controller.view) | |
} | |
func remove(controller: UIViewController) { | |
controller.willMove(toParent: nil) | |
controller.removeFromParent() | |
controller.view.removeFromSuperview() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment