Swift: Custom TabBar with center rounded button
Asked Answered
A

2

9

I try to create custom tabbar like the below picture: enter image description here

Below is the result i get: enter image description here

Below is my current code:

class CustomTabBarController: UITabBarController {


    override func viewDidLoad() {
        super.viewDidLoad()

        let controller1 = UIViewController()
        controller1.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
        let nav1 = UINavigationController(rootViewController: controller1)

        let controller2 = UIViewController()
        controller2.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 2)
        let nav2 = UINavigationController(rootViewController: controller2)

        let controller3 = UIViewController()
        let nav3 = UINavigationController(rootViewController: controller3)
        nav3.title = ""

        let controller4 = UIViewController()
        controller4.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 4)
        let nav4 = UINavigationController(rootViewController: controller4)

        let controller5 = UIViewController()
        controller5.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 5)
        let nav5 = UINavigationController(rootViewController: controller5)

        viewControllers = [nav1, nav2, nav3, nav4, nav5]
        setupMiddleButton()  
    }

    func setupMiddleButton() {
        let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 64, height: 64))
        var menuButtonFrame = menuButton.frame
        menuButtonFrame.origin.y = view.bounds.height - menuButtonFrame.height - 50
        menuButtonFrame.origin.x = view.bounds.width/2 - menuButtonFrame.size.width/2
        menuButton.frame = menuButtonFrame

        menuButton.backgroundColor = UIColor.red
        menuButton.layer.cornerRadius = menuButtonFrame.height/2
        view.addSubview(menuButton)

        menuButton.setImage(UIImage(named: "example"), for: .normal)
        menuButton.addTarget(self, action: #selector(menuButtonAction(sender:)), for: .touchUpInside)

        view.layoutIfNeeded()
    }


    // MARK: - Actions

    @objc private func menuButtonAction(sender: UIButton) {
        selectedIndex = 2
    }

}

How can I draw the shape of the tabbar of the first picture joint

I'm stuck on it that makes several thanks for your help

Anciently answered 28/11, 2019 at 14:53 Comment(4)
The controller is primarily a container view for a UITabBar and the content views, and as a UITabBar is a UIView you should just be able to assign a subclassed TabBar where you override the draw method to lay it out as you like. (Or so I'd expect - it's one of those things I keep meaning to try πŸ™‚) – Kiersten
can u help me in creating tab bar above like i have a default tab bar controller but i want my center tab bar item to be exactly like above – Merlon
Yes look at this medium.com/@philipp307/… – Anciently
github.com/quicklearner4991/… – Bonnett
C
30

You need to customise the tabbar of your CustomTabBarController

Just assign the AppTabBar to the tabbar of your tabBarController for storyboard like this it should works

enter image description here

@IBDesignable
class AppTabBar: UITabBar {

    private var shapeLayer: CALayer?

    override func draw(_ rect: CGRect) {
        self.addShape()
    }

    private func addShape() {
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = createPath()
        shapeLayer.strokeColor = UIColor.lightGray.cgColor
        shapeLayer.fillColor = #colorLiteral(red: 0.9782002568, green: 0.9782230258, blue: 0.9782107472, alpha: 1)
        shapeLayer.lineWidth = 0.5
        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
    }

    func createPath() -> CGPath {
        let height: CGFloat = 86.0
        let path = UIBezierPath()
        let centerWidth = self.frame.width / 2
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: (centerWidth - height ), y: 0))
        path.addCurve(to: CGPoint(x: centerWidth, y: height - 40),
                      controlPoint1: CGPoint(x: (centerWidth - 30), y: 0), controlPoint2: CGPoint(x: centerWidth - 35, y: height - 40))
        path.addCurve(to: CGPoint(x: (centerWidth + height ), y: 0),
                      controlPoint1: CGPoint(x: centerWidth + 35, y: height - 40), 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
    }

    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
    }
}

extension UITabBar {
    override open func sizeThatFits(_ size: CGSize) -> CGSize {
        var sizeThatFits = super.sizeThatFits(size)
        sizeThatFits.height = 74
        return sizeThatFits
    }
}
Chipper answered 28/11, 2019 at 15:11 Comment(5)
Thanks I will let you know :) – Anciently
@MickaelBelhassen the above code worked for u as u wanted – Merlon
Thanks a lot, it's Working Like Charm in my Project – Fowlkes
@Ram Mani, how can I change curve with every selected item? – Refulgent
why each solution in the internet involves storyboards? Could you please describe how to add it programmatically? – Lovins
F
0

For Objective C :

  1. Create class of type UITabBar with name CustomizedTabBarObjeC and place the below code in CustomizedTabBarObjeC.h file.
#import <UIKit/UIKit.h>

@interface CustomizedTabBarObjeC : UITabBar
{
    CALayer *shapeLayer;
}

@end
  1. Use below code for CustomizedTabBarObjeC.m file.
#import "CustomizedTabBarObjeC.h"

@implementation CustomizedTabBarObjeC

- (void)addShape
{
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = [self createPath];
    shapeLayer.strokeColor = [UIColor grayColor].CGColor;
    shapeLayer.fillColor = [UIColor whiteColor].CGColor;
    shapeLayer.lineWidth = 0.5;   
    CALayer *oldShapeLayer;
    if(oldShapeLayer == shapeLayer)
    {
        [self.layer replaceSublayer:oldShapeLayer
                    with:shapeLayer];
    }
    else
    {
        [self.layer insertSublayer:shapeLayer atIndex:0];
    }
    shapeLayer = shapeLayer;
}

-(void) drawRect:(CGRect)rect
{
    [super drawRect:rect];
    [self addShape];
}

-(CGPathRef) createPath
{ 
    float height = 40.0;
    UIBezierPath *path = [UIBezierPath bezierPath];
    float centerWidth = self.frame.size.width/2;
    [path moveToPoint:(CGPoint){0, 0}];
    [path addLineToPoint:(CGPoint){(centerWidth - height * 2), 0}];
    
    // First curve going down
    [path addCurveToPoint:(CGPoint){centerWidth, height} controlPoint1:(CGPoint){(centerWidth - 40), 0} controlPoint2:(CGPoint){(centerWidth - 30), height}];
    
    // Second curve going up
    [path addCurveToPoint:(CGPoint){(centerWidth + height * 2), 0} controlPoint1:(CGPoint){(centerWidth + 30), height} controlPoint2:(CGPoint){(centerWidth + 40), 0}];
    
    // Complete and close the rect path
    [path addLineToPoint:(CGPoint){(self.frame.size.width), 0}];
    [path addLineToPoint:(CGPoint){(self.frame.size.width), (self.frame.size.height)}];
    [path addLineToPoint:(CGPoint){0, (self.frame.size.height)}];
    [path closePath];
    
    return path.CGPath;
}
  1. Go to Tab Bar Controller. Select UITab view and change the name of the class with CustomizedTabBarObjeC.

Screenshot :

Flocculant answered 1/7, 2023 at 6:35 Comment(0)

© 2022 - 2025 β€” McMap. All rights reserved.