4

enter image description here

I attached the View image. I want to achieve the small cut in bottom between the buy button and above flight information view.

Yasheed Mohammed
  • 187
  • 1
  • 14

2 Answers2

8

I think the easiest way would be to create 2 circles as plain UIView instances and set their center as the left and right edges of the parent view respectively.

Since you set clipsToBounds to true, they will be clipped and only half of them will be visible on the screen.

public class TestView: UIView {

    private let leftCircle = UIView(frame: .zero)
    private let rightCircle = UIView(frame: .zero)

    public var circleY: CGFloat = 0
    public var circleRadius: CGFloat = 0

    public override init(frame: CGRect) {
        super.init(frame: frame)
        clipsToBounds = true
        addSubview(leftCircle)
        addSubview(rightCircle)
    }

    public override func layoutSubviews() {
        super.layoutSubviews()

        leftCircle.frame = CGRect(x: -circleRadius, y: circleY,
                                  width: circleRadius * 2 , height: circleRadius * 2)
        leftCircle.layer.masksToBounds = true
        leftCircle.layer.cornerRadius = circleRadius

        rightCircle.frame = CGRect(x: bounds.width - circleRadius, y: circleY,
                                   width: circleRadius * 2 , height: circleRadius * 2)
        rightCircle.layer.masksToBounds = true
        rightCircle.layer.cornerRadius = circleRadius
    }
}

I've created a sample project demonstrating that. Here is how it looks in my simulator (iPhone SE 11.2):

enter image description here

Ozgur Vatansever
  • 49,246
  • 17
  • 84
  • 119
  • In tableViewCell, this is not working. The circle shows but not in center. override func layoutSubviews() { super.layoutSubviews() passView.circleY = passView.frame.height * 0.5 } – Ashu May 01 '20 at 06:55
  • In this way, we will not be able to add shadow to view, it will go over circles and will look odd, do you have any solution for this? – Emre Akcan Nov 03 '20 at 18:30
0

I had to do this with shadows. I tried creating a layer and subtracting another layer from it using evenOdd fillRule, however that didn't work since I need a specific path for shadows and evenOdd applies to the filling in the path instead.

In the end I just created the path manually

func setShadowPath() {
  let path = UIBezierPath()
  path.move(to: bounds.origin)
  path.addLine(to: CGPoint(x: cutoutView.frame.minX, y: bounds.minY))
  path.addArc(withCenter: CGPoint(x: cutoutView.frame.midX, y: bounds.minY),
                radius: cutoutView.bounds.width/2, startAngle: .pi, endAngle: 0, clockwise: false)
  path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
  path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
  path.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
  path.close()
    
  layer.shadowPath = path.cgPath
}

I created a "cutoutView" in my xib so I could trace around it easily.

That makes the shadow the correct shape, and then in order to create the cut itself I just created a layer using that same path

func setupBackground() {
  let backgroundLayer = CAShapeLayer()
  backgroundLayer.path = layer.shadowPath
  backgroundLayer.fillColor = UIColor.white.cgColor
  layer.insertSublayer(backgroundLayer, at: 0)
}
Cameron Porter
  • 801
  • 6
  • 15