First download the starter project from the below link:
Open the project and run, we will see as below images in the simulator.
In this project we have Home View controller to display list of places, Detail view controller for place detail & Account view controller for second tab.
Let’s dive into the goal.
First create new swift file subclass of UIView, name it TabBarSwitchView.swift.
In this view we are going add switch.
Replace TabBarSwitchView class with the following code:
import UIKit class TabBarSwitchView: UIView { let onColor = UIColor(hex: 0xF9CF2D) let offColor = UIColor.white let deselectColor = UIColor(hex: 0xBFBFBF) let bgColor = UIColor(hex: 0x404040) var travellerLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false return v }() var hostLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false return v }() var switchButton: UISwitch = { let v = UISwitch() v.isUserInteractionEnabled = false v.translatesAutoresizingMaskIntoConstraints = false return v }() var ison: Bool = false { didSet { isTraveller = !ison switchButton.setOn(ison, animated: true) if ison { hostLabel.textColor = onColor travellerLabel.textColor = deselectColor }else { hostLabel.textColor = deselectColor travellerLabel.textColor = offColor } } } override init(frame: CGRect) { super.init(frame: frame) setupViews() } let scale:CGFloat = 0.6 func setupViews() { self.backgroundColor = bgColor self.addSubview(switchButton) switchButton.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true switchButton.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true switchButton.onTintColor = onColor switchButton.tintColor = UIColor.white switchButton.thumbTintColor = bgColor switchButton.layoutIfNeeded() switchButton.backgroundColor = offColor switchButton.layer.cornerRadius = 16 switchButton.transform = CGAffineTransform(scaleX: scale, y: scale) self.addSubview(travellerLabel) travellerLabel.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true travellerLabel.trailingAnchor.constraint(equalTo: switchButton.leadingAnchor, constant: -8).isActive = true travellerLabel.text = "TRAVELLER" travellerLabel.font = UIFont.systemFont(ofSize: 12) travellerLabel.textColor = UIColor.white self.addSubview(hostLabel) hostLabel.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true hostLabel.leadingAnchor.constraint(equalTo: switchButton.trailingAnchor, constant: 8).isActive = true hostLabel.text = "HOST" hostLabel.font = UIFont.systemFont(ofSize: 12) hostLabel.textColor = onColor } override func layoutSubviews() { super.layoutSubviews() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } }
Next create new view controller and name it as TabBarRootVC.swift.
Replace code with following code:
import UIKit var isTraveller = false class TabBarRootVC: UIViewController { private lazy var tabBarVC: CustomTabBarVC = { var viewController = CustomTabBarVC() return viewController }() var bottomHeight: CGFloat { guard #available(iOS 11.0, *), let window = UIApplication.shared.keyWindow else { return 0 } return window.safeAreaInsets.bottom } var switchView: TabBarSwitchView = { let v = TabBarSwitchView() v.translatesAutoresizingMaskIntoConstraints = false return v }() var hideBottomBar: Bool = false { didSet { if hideBottomBar { heightConstraint.constant = 0 }else { heightConstraint.constant = 32 + bottomHeight } UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } } var heightConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() setupViews() } func setupViews() { self.view.backgroundColor = UIColor.white self.view.addSubview(switchView) switchView.edges([.left, .right, .bottom], to: self.view, offset: .zero) heightConstraint = switchView.heightAnchor.constraint(equalToConstant: 32 + bottomHeight) heightConstraint.isActive = true switchView.ison = false switchView.isUserInteractionEnabled = true switchView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(switchViewTapped(recognizer:)))) addChild(tabBarVC) self.view.addSubview(tabBarVC.view) tabBarVC.view.translatesAutoresizingMaskIntoConstraints = false tabBarVC.view.edges([.left, .right, .top], to: self.view, offset: .zero) tabBarVC.view.bottomAnchor.constraint(equalTo: switchView.topAnchor, constant: 0).isActive = true tabBarVC.didMove(toParent: self) if !hideBottomBar { heightConstraint.constant = 32 + bottomHeight }else { heightConstraint.constant = 0 } } @objc func switchViewTapped(recognizer: UITapGestureRecognizer) { switchView.ison = !switchView.ison isTraveller = !switchView.ison NotificationCenter.default.post(name: Notification.Name(rawValue: "switchChanged"), object: nil) } }
Open utilities file and add the following extension :
extension UIViewController { func hideBottomSwitch(_ hide: Bool) { if let customTab = self.tabBarController as? CustomTabBarVC { customTab.hideSwitch = hide } } }
Open CustomTabBarVC.swift file and add the following code before viewDidLoad() :
var hideSwitch: Bool = false { didSet { print("view") if let parentVc = self.parent as? TabBarRootVC { parentVc.hideBottomBar = hideSwitch } } }
Open the HomeViewController.swift file and replace all code with the following:
import UIKit class HomeViewController: UIViewController { var tableView: UITableView = { let v = UITableView() v.translatesAutoresizingMaskIntoConstraints = false return v }() var dataSource = [Place]() override func viewDidLoad() { super.viewDidLoad() self.navigationItem.title = "Home" dataSource = [Place(name: "Ocean view during daylight", hostName: "Carey", imageName: "Ocean", createdOn: "23th Mar 2019"), Place(name: "Coconut palm trees", hostName: "Stark", imageName: "Trees", createdOn: "13th Mar 2019"), Place(name: "Trees in park", hostName: "Micheal", imageName: "Park", createdOn: "28th Feb 2019"), Place(name: "Water under sunset", hostName: "Shiny", imageName: "Sunset", createdOn: "16th Feb 2019"), Place(name: "Green trees beside roadway", hostName: "Nina", imageName: "Forest", createdOn: "1st Feb 2019")] setupViews() NotificationCenter.default.addObserver(self, selector: #selector(switchChanged), name: Notification.Name(rawValue: "switchChanged"), object: nil) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.hideBottomSwitch(false) } func setupViews() { self.navigationController?.navigationBar.isTranslucent = false view.addSubview(tableView) tableView.edges([.all], to: view.safeAreaLayoutGuide, offset: .zero) tableView.contentInsetAdjustmentBehavior = .never tableView.separatorStyle = .singleLine tableView.separatorInset = .zero tableView.delegate = self tableView.dataSource = self tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CellIds.hostCellId) tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CellIds.travellerCellId) } @objc func switchChanged() { self.tableView.reloadData() } } extension HomeViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return 80 } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let vc = DetailViewController() vc.place = dataSource[indexPath.row] vc.hidesBottomBarWhenPushed = true self.hideBottomSwitch(true) self.navigationController?.pushViewController(vc, animated: true) } } extension HomeViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataSource.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if isTraveller { // Traveller Cell let cell = tableView.dequeueReusableCell(withIdentifier: CellIds.travellerCellId, for: indexPath) as! CustomTableViewCell let itemAtIndex = dataSource[indexPath.row] cell.imgView.image = UIImage(named: itemAtIndex.imageName) cell.txtLabel.text = itemAtIndex.name cell.subtitleLabel.text = itemAtIndex.hostName cell.selectionStyle = .none return cell }else { // Host Cell let cell = tableView.dequeueReusableCell(withIdentifier: CellIds.hostCellId, for: indexPath) as! CustomTableViewCell let itemAtIndex = dataSource[indexPath.row] cell.imgView.image = UIImage(named: itemAtIndex.imageName) cell.txtLabel.text = itemAtIndex.name cell.subtitleLabel.text = itemAtIndex.createdOn cell.selectionStyle = .none return cell } } }
Now run the project we will see output as following:
Download the finished project from the following link: