如何填充 UIBezierPath 中的重叠部分?

Posted

技术标签:

【中文标题】如何填充 UIBezierPath 中的重叠部分?【英文标题】:How to fill overlapped parts in UIBezierPath? 【发布时间】:2019-01-04 11:03:13 【问题描述】:

我想在裁剪矩形的周围绘制蒙版,它在角落有夹点,我试图用组合的 UIBezierPath 填充矩形内部,例如:4 个圆形和 1 个矩形,而不是将此路径分配给 CAShapeLayer 以将其用作在我看来子层。到目前为止,它填充所需区域只是重叠部分(当我们在矩形上附加圆圈时)未填充(所有角落的四分之一三角形),所以我尝试使用 combinedPath.usesEvenOddFillRule = false - combinedPath.fill() - combinedPath.close() 但它们都没有使用我!所以我需要填写这些部分也有人可以帮助我吗?

你可以从这个link查看图片

我的代码:

    // draw mask
    let path = UIBezierPath(rect: viewBackground.bounds)

    let maskRect = CGRect(x: imgView.frame.origin.x + roiRect.minX * rate, y: imgView.frame.origin.y + roiRect.minY * rate, width: roiRect.width * rate, height: roiRect.height * rate)
    // First apth is for rectangle
    let rectPath = UIBezierPath(rect: maskRect)
    path.append(rectPath)

    // and these paths for corners
    let cornerMaskCircleSize: CGFloat = circleSize/2
    let maskTopLeftCornerPath = UIBezierPath(ovalIn: CGRect(x: maskRect.minX - cornerMaskCircleSize/2, y: maskRect.minY - cornerMaskCircleSize/2, width: cornerMaskCircleSize, height: cornerMaskCircleSize))
    let maskTopRightCornerPath = UIBezierPath(ovalIn: CGRect(x: maskRect.maxX - cornerMaskCircleSize/2, y: maskRect.minY - cornerMaskCircleSize/2, width: cornerMaskCircleSize, height: cornerMaskCircleSize))
    let maskBottomRightCornerPath = UIBezierPath(ovalIn: CGRect(x: maskRect.maxX - cornerMaskCircleSize/2, y: maskRect.maxY - cornerMaskCircleSize/2, width: cornerMaskCircleSize, height: cornerMaskCircleSize))
    let maskBottomLeftCornerPath = UIBezierPath(ovalIn: CGRect(x: maskRect.minX - cornerMaskCircleSize/2, y: maskRect.maxY - cornerMaskCircleSize/2, width: cornerMaskCircleSize, height: cornerMaskCircleSize))

    // Combining all of them in one path
    path.append(maskTopLeftCornerPath)
    path.append(maskTopRightCornerPath)
    path.append(maskBottomRightCornerPath)
    path.append(maskBottomLeftCornerPath)
    path.usesEvenOddFillRule = true
    path.fill()
    path.close()

    cropMask.removeFromSuperlayer()
    cropMask.bounds = viewBackground.frame
    cropMask.position = viewBackground.center
    cropMask.path = path.cgPath
    cropMask.fillRule = .evenOdd
    cropMask.fillColor = UIColor.init(hexString: "#212f41").cgColor
    cropMask.opacity = 0.6

    viewBackground.layer.addSublayer(cropMask)

【问题讨论】:

【参考方案1】:

经过 5 个小时的研究,我终于找到了这个 extension,它以不同的方式解决了我的问题,这个扩展有助于绘制四分之三的圆,所以我用它来绘制从矩形角边为空的圆。

这是一个使用示例代码:

fileprivate func drawMask() 

    let rectPath = UIBezierPath(rect: CGRect(x: 100, y: 200, width: 175, height: 150))
    let leftTopCornerPath = UIBezierPath(quarterCircleCentre: CGPoint(x: 100, y: 200), radius: 10, quadrant: .BottomRightThreeQuarterCircle)
    let rightTopCornerPath = UIBezierPath(quarterCircleCentre: CGPoint(x: 275, y: 200), radius: 10, quadrant: .BottomLeftThreeQuarterCircle)
    let leftBottomCornerPath = UIBezierPath(quarterCircleCentre: CGPoint(x: 100, y: 350), radius: 10, quadrant: .TopRightThreeQuarterCircle)
    let rightBottomCornerPath = UIBezierPath(quarterCircleCentre: CGPoint(x: 275, y: 350), radius: 10, quadrant: .TopLeftThreeQuarterCircle)

    let combined = UIBezierPath(rect: self.view.frame)
    combined.append(rectPath)
    combined.append(leftTopCornerPath)
    combined.append(rightTopCornerPath)
    combined.append(leftBottomCornerPath)
    combined.append(rightBottomCornerPath)

    let maskLayer = CAShapeLayer()
    maskLayer.bounds = self.view.bounds
    maskLayer.position = self.view.center
    maskLayer.path = combined.cgPath
    maskLayer.fillRule = .evenOdd
    maskLayer.fillColor = UIColor.black.cgColor
    maskLayer.opacity = 0.5

    self.view.layer.addSublayer(maskLayer)


扩展

extension UIBezierPath 


enum QuarterCircleQuadrant 
    case TopLeft, BottomLeft, TopRight, BottomRight, TopLeftThreeQuarterCircle, BottomRightThreeQuarterCircle, BottomLeftThreeQuarterCircle, TopRightThreeQuarterCircle
    var startAngle: CGFloat 
        switch self 
        case .BottomLeft:
            return CGFloat(Double.pi)
        case .BottomLeftThreeQuarterCircle:
            return CGFloat(Double.pi)
        case .TopLeft:
            return CGFloat(Double.pi)
        case .BottomRight:
            return 0
        case .TopRight:
            return 0
        case .TopRightThreeQuarterCircle:
            return 0
        case .TopLeftThreeQuarterCircle:
            return CGFloat(Double.pi)
        case .BottomRightThreeQuarterCircle:
            return 0
        

    
    var endAngle: CGFloat 
        switch self 
        case .BottomLeft:
            return CGFloat(Double.pi/2)
        case .BottomLeftThreeQuarterCircle:
            return CGFloat(Double.pi/2)
        case .TopLeft:
            return CGFloat(Double.pi) * 1.5
        case .BottomRight:
            return CGFloat(Double.pi/2)
        case .TopRight:
            return CGFloat(Double.pi) * 1.5
        case .TopRightThreeQuarterCircle:
            return CGFloat(Double.pi) * 1.5
        case .TopLeftThreeQuarterCircle:
            return CGFloat(Double.pi) * 1.5
        case .BottomRightThreeQuarterCircle:
            return CGFloat(Double.pi/2)
        


    

    var clockwise: Bool 
        switch self 
        case .BottomLeft:
            return false
        case .TopLeft:
            return true
        case .BottomRight:
            return true
        case .TopRight:
            return false
        case .BottomLeftThreeQuarterCircle:
            return true
        case .TopRightThreeQuarterCircle:
            return true
        case .TopLeftThreeQuarterCircle:
            return false
        case .BottomRightThreeQuarterCircle:
            return false
        


    



convenience init(quarterCircleCentre centre:CGPoint, radius:CGFloat, quadrant:QuarterCircleQuadrant)

    self.init()
    self.move(to: CGPoint(x: centre.x, y:centre.y))
    self.addArc(withCenter: centre, radius:radius, startAngle:quadrant.startAngle, endAngle: quadrant.endAngle, clockwise:quadrant.clockwise)
    self.close()


结果图片 link

【讨论】:

以上是关于如何填充 UIBezierPath 中的重叠部分?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 UIBezierPath 从中心填充

iOS:如何为uibezierpath中的填充设置动画?

UIBezierPath 填充与 CAShapeLayer

如何以给定的顺序动画/填充 UIBezierPath?

如何为 UIBezierPath 上的填充颜色变化设置动画?

如何在 CAShapeLayer 上仅填充形状的一部分