【问题标题】:How to draw rounded rect that wraps around circular button?如何绘制环绕圆形按钮的圆形矩形?
【发布时间】:2020-03-26 03:59:40
【问题描述】:

我想在 swift 中使用贝塞尔路径设计下面屏幕快照的曲线的突出部分。

【问题讨论】:

  • 白色视图右下角
  • 我已经上传了新的图片来表示曲线的部分
  • 是的,我熟悉这个
  • 好的,假设你正在画这个。从右侧顺时针方向,addLine 表示右侧,addCubicCurve 表示圆形边缘,addArc 用于围绕按钮绘制圆弧,另一个 addCubicCurve 表示圆形边缘接近“开始跟踪”按钮的“8 点钟”部分,然后是底部边缘的addLine,然后继续。没有内置函数可以执行此操作...您只需要做一些三角函数来计算在将这些三次贝塞尔曲线和弧线添加到此路径时要使用的点。
  • 我尝试过类似的方法,但没有发现任何成功。

标签: ios swift path uibezierpath bezier


【解决方案1】:

计算右下角那个按钮周围的弧只是一个小三角函数,例如

func updatePath() {
    let buttonCenter = CGPoint(x: bounds.maxX - circleRadius, y: bounds.maxY - circleRadius)

    circleShapeLayer.path = UIBezierPath(arcCenter: buttonCenter, radius: circleRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath // red

    let angle1 = acos((circleRadius - cornerRadius) / (circleRadius + spaceRadius + cornerRadius))
    let angle2 = acos((circleRadius - bottomDistance - cornerRadius) / (circleRadius + spaceRadius + cornerRadius))

    let arc1Center = CGPoint(x: bounds.maxX - cornerRadius,
                             y: buttonCenter.y - (circleRadius + cornerRadius + spaceRadius) * sin(angle1))

    let path = UIBezierPath()

    path.move(to: CGPoint(x: bounds.maxX, y: bounds.minY + cornerRadius))
    path.addArc(withCenter: arc1Center, radius: cornerRadius, startAngle: 0, endAngle: .pi / 2 + (.pi / 2 - angle1), clockwise: true) // blue
    path.addArc(withCenter: buttonCenter, radius: circleRadius + spaceRadius, startAngle: 2 * .pi - angle1, endAngle: .pi / 2 + angle2, clockwise: false) // green

    let arc2Center = CGPoint(x: buttonCenter.x - (circleRadius + cornerRadius + spaceRadius) * sin(angle2), y: bounds.maxY - bottomDistance - cornerRadius)

    path.addArc(withCenter: arc2Center, radius: cornerRadius, startAngle: -(.pi / 2 - angle2), endAngle: .pi / 2, clockwise: true) // yellow
    path.addArc(withCenter: CGPoint(x: bounds.minX + cornerRadius, y: bounds.maxY - (bottomDistance + cornerRadius)), radius: cornerRadius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) // cyan
    path.addArc(withCenter: CGPoint(x: bounds.minX + cornerRadius, y: bounds.minY + cornerRadius), radius: cornerRadius, startAngle: .pi, endAngle: .pi * 3 / 2, clockwise: true) // white
    path.addArc(withCenter: CGPoint(x: bounds.maxX - cornerRadius, y: bounds.minY + cornerRadius), radius: cornerRadius, startAngle: .pi * 3 / 2, endAngle: 2 * .pi, clockwise: true) // black
    path.close()

    backgroundShapeLayer.path = path.cgPath
}

产量:

或者,如果你想匹配上面的笔画,这里用颜色编码到上面代码中的cmets:


例如:

@IBDesignable
class BackgroundView: UIView {
    @IBInspectable var cornerRadius:   CGFloat = 10 { didSet { setNeedsLayout() } }
    @IBInspectable var spaceRadius:    CGFloat = 10 { didSet { setNeedsLayout() } }
    @IBInspectable var circleRadius:   CGFloat = 50 { didSet { setNeedsLayout() } }
    @IBInspectable var bottomDistance: CGFloat = 30 { didSet { setNeedsLayout() } }

    private let backgroundShapeLayer: CAShapeLayer = {
        let shapeLayer = CAShapeLayer()
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.strokeColor = UIColor.clear.cgColor
        return shapeLayer
    }()

    private let circleShapeLayer: CAShapeLayer = {
        let shapeLayer = CAShapeLayer()
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.strokeColor = UIColor.clear.cgColor
        return shapeLayer
    }()

    override init(frame: CGRect = .zero) {
        super.init(frame: frame)
        configure()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        configure()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        updatePath()
    }
}

private extension BackgroundView {

    func configure() {
        layer.addSublayer(circleShapeLayer)
        layer.addSublayer(backgroundShapeLayer)
    }

    func updatePath() {
        let buttonCenter = CGPoint(x: bounds.maxX - circleRadius, y: bounds.maxY - circleRadius)

        circleShapeLayer.path = UIBezierPath(arcCenter: buttonCenter, radius: circleRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath

        let angle1 = acos((circleRadius - cornerRadius) / (circleRadius + spaceRadius + cornerRadius))
        let angle2 = acos((circleRadius - bottomDistance - cornerRadius) / (circleRadius + spaceRadius + cornerRadius))

        let arc1Center = CGPoint(x: bounds.maxX - cornerRadius,
                                 y: buttonCenter.y - (circleRadius + cornerRadius + spaceRadius) * sin(angle1))

        let path = UIBezierPath()

        path.move(to: CGPoint(x: bounds.maxX, y: bounds.minY + cornerRadius))
        path.addArc(withCenter: arc1Center, radius: cornerRadius, startAngle: 0, endAngle: .pi / 2 + (.pi / 2 - angle1), clockwise: true)
        path.addArc(withCenter: buttonCenter, radius: circleRadius + spaceRadius, startAngle: 2 * .pi - angle1, endAngle: .pi / 2 + angle2, clockwise: false)

        let arc2Center = CGPoint(x: buttonCenter.x - (circleRadius + cornerRadius + spaceRadius) * sin(angle2), y: bounds.maxY - bottomDistance - cornerRadius)

        path.addArc(withCenter: arc2Center, radius: cornerRadius, startAngle: -(.pi / 2 - angle2), endAngle: .pi / 2, clockwise: true)
        path.addArc(withCenter: CGPoint(x: bounds.minX + cornerRadius, y: bounds.maxY - (bottomDistance + cornerRadius)), radius: cornerRadius, startAngle: .pi / 2, endAngle: .pi, clockwise: true)
        path.addArc(withCenter: CGPoint(x: bounds.minX + cornerRadius, y: bounds.minY + cornerRadius), radius: cornerRadius, startAngle: .pi, endAngle: .pi * 3 / 2, clockwise: true)
        path.addArc(withCenter: CGPoint(x: bounds.maxX - cornerRadius, y: bounds.minY + cornerRadius), radius: cornerRadius, startAngle: .pi * 3 / 2, endAngle: 2 * .pi, clockwise: true)
        path.close()

        backgroundShapeLayer.path = path.cgPath
    }
}

【讨论】:

    【解决方案2】:

    您可以在mac上使用Paint code应用程序,使用钢笔工具绘制曲线,然后复制它的结果,因为该应用程序提供Drawings-to-code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-21
      • 2013-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      相关资源
      最近更新 更多