Curved Tabbar with a round middle button – Swift

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.pngScreenshot 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!


Also published on Medium.

By |2019-04-02T17:09:47+00:00March 14th, 2019|Categories: iOS Tutorials|Tags: , , |2 Comments

2 Comments

  1. Oscar August 4, 2019 at 11:23 am - Reply

    I have used this, and works fine but, If you want to get text with icons in landscape mode the centered item, even if there’s no text is not in de middle

  2. jeevan October 4, 2019 at 9:57 am - Reply

    rwerwer

Leave A Comment