// Shape with indented Notched Tab View
// based on: DuncanMC's https://github.com/DuncanMC/ShapeWithTab
class ShapeWithNotchedTabView: UIView {
var cornerRadius: CGFloat = 20
var tabRadius: CGFloat = 60
var roundedCorners: Bool = true { didSet { setNeedsLayout() } }
var shapeLayer = CAShapeLayer()
func buildShapeLayerPath() -> CGPath {
let boxWidth = bounds.size.width
let boxHeight = bounds.size.height
// These are the corners of the view's primary rectangle
// top-right
let point1 = CGPoint(x: boxWidth, y: 0)
// bottom-right
let point2 = CGPoint(x: boxWidth, y: boxHeight)
// bottom-left
let point3 = CGPoint(x: 0, y: boxHeight)
// top-left
let point4 = CGPoint(x: 0, y: 0)
// These are the corners of the "tab notch" that is inset from the top of the view
let tabPoint1 = CGPoint(x: boxWidth / 2 - tabRadius, y: 0)
let tabPoint2 = CGPoint(x: boxWidth / 2, y: tabRadius * 2)
let tabPoint3 = CGPoint(x: boxWidth / 2 + tabRadius , y: 0)
let path = CGMutablePath()
// if we want rounded corners
if roundedCorners {
path.move(to: CGPoint(x: boxWidth, y: boxHeight - cornerRadius))
path.addArc(tangent1End: point2,
tangent2End: point3,
radius: cornerRadius)
path.addArc(tangent1End: point3,
tangent2End: point4,
radius: cornerRadius)
path.addArc(tangent1End: point4,
tangent2End: tabPoint1,
radius: cornerRadius)
} else {
path.move(to: point1)
path.addLine(to: point2)
path.addLine(to: point3)
path.addLine(to: point4)
}
// Draw the corner that curves around to our
// indented "circle tab notch" at the top
// of the shape
path.addArc(tangent1End: tabPoint1,
tangent2End: tabPoint2,
radius: cornerRadius)
// Draw the "circle tab notch"
path.addArc(tangent1End: tabPoint2,
tangent2End: tabPoint3,
radius: tabRadius)
// Draw the corner from the circle tab notch back to the top of the rect
path.addArc(tangent1End: tabPoint3,
tangent2End: point1,
radius: cornerRadius)
if roundedCorners {
// Draw the rest of the rounded rectangle
path.addArc(tangent1End: point1,
tangent2End: point2,
radius: cornerRadius)
} else {
// Draw the rest of the rectangle
path.addLine(to: point1)
}
path.closeSubpath()
return path
}
func doInitSetup() {
self.layer.addSublayer(shapeLayer)
// Configure a shape layer to draw an outline
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 2
}
override init(frame: CGRect) {
super.init(frame: frame)
self.doInitSetup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.doInitSetup()
}
public func updateShapeLayerPath() {
let path = buildShapeLayerPath()
shapeLayer.path = path
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.frame = bounds
updateShapeLayerPath()
}
}
// example controller
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
let v = ShapeWithNotchedTabView()
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
NSLayoutConstraint.activate([
v.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
v.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0),
v.centerYAnchor.constraint(equalTo: view.centerYAnchor),
v.heightAnchor.constraint(equalToConstant: 120.0),
])
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.numberOfLines = 0
label.text = "Tap anywhere to toggle rounded corners"
view.addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 40.0),
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -40.0),
label.topAnchor.constraint(equalTo: v.bottomAnchor, constant: 20.0),
])
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let v = view.subviews.first as? ShapeWithNotchedTabView {
v.roundedCorners.toggle()
}
}
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎