如何用 UIBezierPath 做这个形状

How to do this shape with UIBezierPath

我正在尝试使用 UIBezierPath 将我的 UIView 转换为这种形状,目前我只能做左下角,寻求帮助以添加其他角。

仅左下角代码。

        let mask = CAShapeLayer()
        mask.frame = self.innerLayout.layer.bounds

        let path = UIBezierPath()
        let radius: CGFloat = 50
        let rect = mask.bounds

        path.move(to: rect.origin)
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.minX + radius, y: rect.maxY))
        path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: 0, endAngle: CGFloat(M_PI_2 * 3), clockwise: false)

        mask.path = path.cgPath
        self.innerLayout.layer.mask = mask

我做了几次添加其他角的试验,但我的 UIView 得到了有趣的形状。我只是通过复制和粘贴(并更改原点)添加了这个,我相信我们会使用这部分代码 4 次来添加 4 个角

    path.move(to: CGPoint(x: rect.maxX, y: rect.maxY)
    path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
    path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
    path.addLine(to: CGPoint(x: rect.minX + radius, y: rect.maxY))
    path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: 0, endAngle: CGFloat(M_PI_2 * 3), clockwise: false)

下面是 Playground 中 运行 的完整示例。这样的几何形状总是很棘手。很容易弄错坐标或者弧线走错方向。

import UIKit
import PlaygroundSupport

class ConcaveConrnerViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let frame = CGRect(x: 100, y: 200, width: 200, height: 200)
        let subView = UIView(frame: frame)
        subView.backgroundColor = .red
        
        let mask = CAShapeLayer()
        mask.frame = subView.layer.bounds

        let path = UIBezierPath()
        let radius: CGFloat = 50
        let rect = mask.bounds

        path.move(to: CGPoint(x: rect.minX + radius, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX - radius, y: rect.minY))
        path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: CGFloat(Double.pi / 2 * 2), endAngle: CGFloat(Double.pi / 2 * 3), clockwise: false)
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - radius))
        path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius, startAngle: CGFloat(Double.pi / 2 * 1), endAngle: CGFloat(Double.pi / 2 * 2), clockwise: false)
        path.addLine(to: CGPoint(x: rect.minX + radius, y: rect.maxY))
        path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: CGFloat(Double.pi / 2 * 0), endAngle: CGFloat(Double.pi / 2 * 1), clockwise: false)
        path.addLine(to: CGPoint(x: rect.minX, y: rect.minY + radius))
        path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: CGFloat(Double.pi / 2 * 3), endAngle: CGFloat(Double.pi / 2 * 0), clockwise: false)
        path.close()

        mask.path = path.cgPath
        subView.layer.mask = mask
        
        view.addSubview(subView)
        self.view = view
    }
}

PlaygroundPage.current.liveView = ConcaveConrnerViewController()