Curved Tabbar with a round middle button — Swift

Zeba Rahman
fabcoding
Published in
3 min readMar 14, 2019

Tab Bars are an essential component and one of the most commonly used features in iOS app design. It provides easy navigation and enhances the look and feel.

Enhancing the Tab bar with customized sleek designs can instantly make your app stand out.

Set up the storyboard…

I assume you have created your new iOS project. Before we start, just set up your viewcontrollers.

  1. Add a TabBarController into your Storyboard.
  2. Add 3 or 5 ViewControllers and link them to the TabBarController

Create a new class MyTabBarCtrl.swift

import UIKit
class MyTabBarCtrl: UITabBarController, UITabBarControllerDelegate {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}

override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
}

Go back to storyboard, and change your TabBarController class to MyTabBarCtrl.

Draw the TabBar shape

We need to subclass the TabBar. Create a new class MyTabBar.swift

import UIKit
@IBDesignable
class MyTabBar: UITabBar {

}

The shape layer was inspired from this article. Add the following to MyTabBar class.

private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.strokeColor = UIColor.lightGray.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.lineWidth = 1.0

//The below 4 lines are for shadow above the bar. you can skip them if you do not want a shadow
shapeLayer.shadowOffset = CGSize(width:0, height:0)
shapeLayer.shadowRadius = 10
shapeLayer.shadowColor = UIColor.gray.cgColor
shapeLayer.shadowOpacity = 0.3

if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer, at: 0)
}
self.shapeLayer = shapeLayer
}
override func draw(_ rect: CGRect) {
self.addShape()
}
func createPath() -> CGPath {
let height: CGFloat = 37.0
let path = UIBezierPath()
let centerWidth = self.frame.width / 2
path.move(to: CGPoint(x: 0, y: 0)) // start top left
path.addLine(to: CGPoint(x: (centerWidth - height * 2), y: 0)) // the beginning of the trough

path.addCurve(to: CGPoint(x: centerWidth, y: height),
controlPoint1: CGPoint(x: (centerWidth - 30), y: 0), controlPoint2: CGPoint(x: centerWidth - 35, y: height))

path.addCurve(to: CGPoint(x: (centerWidth + height * 2), y: 0),
controlPoint1: CGPoint(x: centerWidth + 35, y: height), controlPoint2: CGPoint(x: (centerWidth + 30), y: 0))

path.addLine(to: CGPoint(x: self.frame.width, y: 0))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height))
path.addLine(to: CGPoint(x: 0, y: self.frame.height))
path.close()

return path.cgPath
}

That’s all for the shape!

But there’s a tiny problem. The middle button is raised a little beyond the bounds of the TabBar view. By default, click events won’t be caught on views outside of the bounds of it’s superview. To solve this, we override hitTest:withEvent: method. Add thin in the same MyTabBar class

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard !clipsToBounds && !isHidden && alpha > 0 else { return nil }
for member in subviews.reversed() {
let subPoint = member.convert(point, from: self)
guard let result = member.hitTest(subPoint, with: event) else { continue }
return result
}
return nil
}

Go back to your storyboard. Select TabBar object under MyTabBarCtrl. and under Identity Inspector, Select MyTabBar,

Screenshot 2019-02-22 at 11.46.29 PM.png
Screenshot 2019-02-22 at 11.48.43 PM.png

The shape of the tab bar should now be visible in your view controller in the storyboard.

Design the middle button

Open MyTabBarCtrl.swift and add this function

// TabBarButton – Setup Middle Button
func setupMiddleButton() {

let middleBtn = UIButton(frame: CGRect(x: (self.view.bounds.width / 2)-25, y: -20, width: 50, height: 50))

//STYLE THE BUTTON YOUR OWN WAY
middleBtn.setIcon(icon: .fontAwesomeSolid(.home), iconSize: 20.0, color: UIColor.white, backgroundColor: UIColor.white, forState: .normal)
middleBtn.applyGradient(colors: colorBlueDark.cgColor,colorBlueLight.cgColor])

//add to the tabbar and add click event
self.tabBar.addSubview(middleBtn)
middleBtn.addTarget(self, action: #selector(self.menuButtonAction), for: .touchUpInside)

self.view.layoutIfNeeded()
}

// Menu Button Touch Action
@objc func menuButtonAction(sender: UIButton) {
self.selectedIndex = 2 //to select the middle tab. use "1" if you have only 3 tabs.
}

For setIcon, I used this library.

For the button gradient, check out this tutorial.

Call this function in your TabBarController’s viewDidLoad().

That’s all!

Originally published at Fabcoding.

--

--