So this is the navigation my designer made for our project. Height of the TabBar is 70.
What I have tried so far. My attempt was based on tutorial from Philipp Weiss.
https://betterprogramming.pub/draw-a-custom-ios-tabbar-shape-27d298a7f4fa
Its based on idea of creating custom IBDesignable UITabBar class and overriding draw method.
@IBDesignable
class CustomizedTabBar: UITabBar {
private var shapeLayer: CALayer?
override func draw(_ rect: CGRect) {
self.addShape()
}
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.strokeColor = UIColor.blueMenu2.cgColor
shapeLayer.fillColor = UIColor.blueMenu2.cgColor
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
}
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
// first curve down
path.addCurve(to: CGPoint(x: centerWidth, y: height),
controlPoint1: CGPoint(x: (centerWidth - 30), y: 0), controlPoint2: CGPoint(x: centerWidth - 35, y: height))
// second curve up
path.addCurve(to: CGPoint(x: (centerWidth + height * 2), y: 0),
controlPoint1: CGPoint(x: centerWidth + 35, y: height), controlPoint2: CGPoint(x: (centerWidth + 30), y: 0))
// complete the rect
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
}
I was trying to edit bezier path to reach my goal but with no success. I am not sure if this approach can work for this specific TabBar design.
Setting height of navigation to 70 was without problem.
@IBInspectable var height: CGFloat = 70
override open func sizeThatFits(_ size: CGSize) -> CGSize {
guard let window = UIApplication.shared.keyWindow else {
return super.sizeThatFits(size)
}
var sizeThatFits = super.sizeThatFits(size)
if #available(iOS 11.0, *) {
sizeThatFits.height = height + window.safeAreaInsets.bottom
} else {
sizeThatFits.height = height
}
return sizeThatFits
}
How can I create this curved TabBar?
Do u know how to make similar shape just by using bezier curves?
To create a UIBezierPath
for your desired shape...
Here is some sample code - it's a UIView
subclass, with all the path elements in layoutSubviews()
:
class TabBarShapeView: UIView {
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.gray.cgColor
shapeLayer.lineWidth = 1
}
override func layoutSubviews() {
super.layoutSubviews()
let middleRad: CGFloat = bounds.height - 10.0
let cornerRad: CGFloat = 12.0
let pth = UIBezierPath()
let topLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.minY + cornerRad)
let topRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY + cornerRad)
let botRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.maxY - cornerRad)
let botLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY - cornerRad)
var pt: CGPoint!
// 1
pt = CGPoint(x: bounds.minX, y: bounds.minY + cornerRad)
pth.move(to: pt)
// c1
pth.addArc(withCenter: topLeftC, radius: cornerRad, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)
// 2
pt = CGPoint(x: bounds.midX - middleRad, y: bounds.minY)
pth.addLine(to: pt)
// c2
pt.y += middleRad * 0.5
pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)
// c3
pt.x += middleRad * 1.0
pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: 0.0, clockwise: false)
// c4
pt.x += middleRad * 1.0
pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)
// 3
pt = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY)
pth.addLine(to: pt)
// c5
pth.addArc(withCenter: topRightC, radius: cornerRad, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)
// 4
pt = CGPoint(x: bounds.maxX, y: bounds.maxY - cornerRad)
pth.addLine(to: pt)
// c6
pth.addArc(withCenter: botRightC, radius: cornerRad, startAngle: 0.0, endAngle: .pi * 0.5, clockwise: true)
// 5
pt = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY)
pth.addLine(to: pt)
// c7
pth.addArc(withCenter: botLeftC, radius: cornerRad, startAngle: .pi * 0.5, endAngle: .pi * 1.0, clockwise: true)
pth.close()
shapeLayer.path = pth.cgPath
}
}