Make Custom Button on Tab Bar Rounded

Make custom button on Tab Bar rounded

Solution

You need to subclass UITabBarController and then add the button above TabBar's view. A button action should trigger UITabBarController tab change by setting selectedIndex.

Code

The code below only is a simple approach, however for a full supporting iPhone (including X-Series)/iPad version you can check the full repository here: EBRoundedTabBarController

class CustomTabBarController: UITabBarController {

// MARK: - View lifecycle

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

// MARK: - Setups

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

Output

Sample Image

Swift: Custom TabBar with center rounded button

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

Sample Image

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

How to make custom tab indicator to be a rounded bar in Jetpack Compose

You applied Modifier.padding between Modifier.clip and Modifier.background, so the rounding is actually applied to the transparent padding. You need to move the padding in front of the clip, or specify the shape with the background:

.background(color = AnkiBlue100, shape = RoundedCornerShape(8.dp))

Read more about why the order of the modifiers matters in this answer

Swift 3 - How do I create a prominent button on a tab bar (e.g. camera button)

One way is to simply add your UIButton on top of UITabBarController with the dummy center view controller.

Here I use storyboard and subclass UITabBarController to add that button:

Sample Image

This is my storyboard, note how the center view controller is just there for space:

Sample Image

With only those code and storyboard, this is the result:

Sample Image

Project here: https://github.com/aunnnn/TestButtonOnTabBar/

Custom Tab Bar, with central button which will be hide by pressed index

I am was created this tab bar, ours need few steps.
Create ViewController and Embed in "TabBarController", then need create TWO class first for "UITabBar" this class contain shape and what you want with "UITabBar", second class for "UITabBarController" for switch between ViewControllers inside we can add animation.... It's need because, my TabBar have 4 tabs and only on LAST tabs I am have Central FAB button with animation, and I am should animate position of my 2 and 3 ui tab bar element when button is appear.

Class for "UITabBar"

import UIKit

@IBDesignable
class CustomizedTabBar: UITabBar {

// MARK:- Variables -
@objc public var centerButtonActionHandler: ()-> () = {}

@IBInspectable public var centerButton: UIButton?
@IBInspectable public var centerButtonColor: UIColor?
@IBInspectable public var centerButtonHeight: CGFloat = 50.0
@IBInspectable public var padding: CGFloat = 5.0
@IBInspectable public var buttonImage: UIImage?
@IBInspectable public var buttonTitle: String?

@IBInspectable public var tabbarColor: UIColor = UIColor.lightGray
@IBInspectable public var unselectedItemColor: UIColor = .init(red: 0.58, green: 0.61, blue: 0.66, alpha: 1.0)
@IBInspectable public var selectedItemColor: UIColor = UIColor.black

public var arc: Bool = true {
didSet {
self.setNeedsDisplay()
}
}

private var shapeLayer: CALayer?

private func addShape() {

let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()


shapeLayer.strokeColor = UIColor.white.cgColor
shapeLayer.fillColor = #colorLiteral(red: 0.96, green: 0.96, blue: 0.96, alpha: 1)
shapeLayer.lineWidth = 1.0

if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer, at: 0)
}


self.shapeLayer = shapeLayer
self.tintColor = centerButtonColor
self.unselectedItemTintColor = unselectedItemColor
self.tintColor = selectedItemColor
self.setupMiddleButton()

}

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

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

func createPath() -> CGPath {

let padding: CGFloat = 5.0
let centerButtonHeight: CGFloat = 53.0

let f = CGFloat(centerButtonHeight / 2.0) + padding
let h = frame.height
let w = frame.width
let halfW = frame.width/2.0
let r = CGFloat(18)
let path = UIBezierPath()
path.move(to: .zero)

if (!arc) {

path.addLine(to: CGPoint(x: halfW-f-(r/2.0), y: 0))

path.addQuadCurve(to: CGPoint(x: halfW-f, y: (r/2.0)), controlPoint: CGPoint(x: halfW-f, y: 0))

path.addArc(withCenter: CGPoint(x: halfW, y: (r/2.0)), radius: f, startAngle: .pi, endAngle: 0, clockwise: false)

path.addQuadCurve(to: CGPoint(x: halfW+f+(r/2.0), y: 0), controlPoint: CGPoint(x: halfW+f, y: 0))
}
path.addLine(to: CGPoint(x: w, y: 0))
path.addLine(to: CGPoint(x: w, y: h))
path.addLine(to: CGPoint(x: 0.0, y: h))
path.close()

return path.cgPath
}

private func setupMiddleButton() {

centerButton = UIButton(frame: CGRect(x: (self.bounds.width / 2)-(centerButtonHeight/2), y: -16, width: centerButtonHeight, height: centerButtonHeight))
centerButton!.setNeedsDisplay()
centerButton!.layer.cornerRadius = centerButton!.frame.size.width / 2.0
centerButton!.setTitle(buttonTitle, for: .normal)
centerButton!.setImage(UIImage(named: "plus"), for: .normal)
centerButton!.backgroundColor = .init(red: 0.07, green: 0.83, blue: 0.05, alpha: 1.0)
centerButton!.tintColor = UIColor.white

self.centerButton!.isHidden = true

if (!self.arc) {

DispatchQueue.main.async {

UIView.transition(with: self.centerButton!, duration: 1,
options: .transitionCrossDissolve,
animations: {

self.centerButton!.isHidden = false

})
}
}


//add to the tabbar and add click event
self.addSubview(centerButton!)
centerButton!.addTarget(self, action: #selector(self.centerButtonAction), for: .touchUpInside)
}

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let buttonRadius: CGFloat = 35
return abs(self.center.x - point.x) > buttonRadius || abs(point.y) > buttonRadius
}

func createPathCircle() -> CGPath {

let radius: CGFloat = 37.0
let path = UIBezierPath()
let centerWidth = self.frame.width / 2

path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: (centerWidth - radius * 2), y: 0))
path.addArc(withCenter: CGPoint(x: centerWidth, y: 0), radius: radius, startAngle: CGFloat(180).degreesToRadians, endAngle: CGFloat(0).degreesToRadians, clockwise: false)
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
}

// Menu Button Touch Action
@objc func centerButtonAction(sender: UIButton) {
self.centerButtonActionHandler()
}

}

extension CGFloat {
var degreesToRadians: CGFloat { return self * .pi / 180 }
var radiansToDegrees: CGFloat { return self * 180 / .pi }
}

And class for UITabBarController

import UIKit

class MyTabBarController: UITabBarController {
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let myTabBar = tabBar as! CustomizedTabBar
if (myTabBar.items?[3] == item) {
myTabBar.arc = false
} else {
myTabBar.arc = true
}
}
}


Related Topics



Leave a reply



Submit