How to Draw Custom Shape Swift?

62 Views Asked by At

I'm trying to create an arrow with rounded corners, but I'm not getting the result I want

private let arrowLayer: CAShapeLayer = {
    let layer = CAShapeLayer()
    layer.fillColor = UIColor.orange.cgColor
    layer.anchorPoint = CGPoint(x: 0.2, y: 0.5)
    layer.lineWidth = 4
    layer.strokeColor = UIColor.orange.cgColor
    layer.fillColor = UIColor.orange.cgColor
    layer.lineCap = .round
    layer.lineJoin = .round

    return layer
}()
override func layoutSubviews() {
    super.layoutSubviews()
    arrowLayer.bounds.size = CGSize(width: bounds.width * 0.27, height: bounds.width * 0.02)
    arrowLayer.position = CGPoint(x: bounds.midX, y: bounds.midY)

    let path = UIBezierPath()
    path.move(to: CGPoint(x: arrowLayer.bounds.width, y: arrowLayer.bounds.height * 0.3))
    path.addLine(to: CGPoint(x: arrowLayer.bounds.width, y: arrowLayer.bounds.height * 0.7))
    path.addLine(to: CGPoint(x: 0.0, y: arrowLayer.bounds.height))
    path.addLine(to: CGPoint(x: 0.0, y: 0.0))
    path.close()

    arrowLayer.path = path.cgPath
}

This is the result I get

enter image description here

I want to get this result

enter image description here

I tried but didn't get the desired result

layer.lineCap = .round
layer.lineJoin = .round
1

There are 1 best solutions below

0
Mojtaba Hosseini On BEST ANSWER

You may need to draw arcs on both sides like:

let minR: CGFloat = 10
let bigR: CGFloat = 20
var path = UIBezierPath()

path.move(to: .init(x: rect.midX - minR, y: minR))
path.addArc(
    withCenter: .init(x: rect.midX, y: minR),
    radius: minR,
    startAngle: .degrees(0),
    endAngle: .degrees(180),
    clockwise: true
)
path.addLine(to: .init(x: rect.midX - bigR, y: rect.maxY - bigR))
path.addArc(
    withCenter: .init(x: rect.midX, y: rect.maxY - bigR),
    radius: bigR,
    startAngle: .degrees(0),
    endAngle: .degrees(180),
    clockwise: false
)
path.move(to: .init(x: rect.midX + bigR, y: rect.maxY - bigR))
path.addLine(to: .init(x: rect.midX + minR, y: minR))
path.addLine(to: .init(x: rect.midX - minR, y: minR))
path.addLine(to: .init(x: rect.midX - bigR, y: rect.maxY - bigR))

Demo

Don't forget to convert radians to degrees:

extension CGFloat {
    static func degrees(_ degrees: Double) -> Double { degrees * .pi / 180 }
}