UIBezierPath的roundedRect存在奇怪的间隙。

huangapple go评论65阅读模式
英文:

UIBezierPath roundedRect has strange gaps

问题

I need to draw a rounded rect. However, at very special corner radius values (between 34 to 37), it causes very strange bugs like the image below. Can someone explain to me why it happened?

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        drawView()
        self.view.backgroundColor = .red
    }

    func drawView() {
        let rect = CGRect(x: 100, y: 100, width: 200, height: 100)
        let borderWidth = 10.0
        let cornerRadius = 34.0
        
        let layer = CAShapeLayer()
        layer.strokeColor = UIColor.green.cgColor
        layer.lineWidth = borderWidth
        layer.fillColor = UIColor.white.cgColor
        
        let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
        
        layer.path = path.cgPath
        
        self.view.layer.addSublayer(layer)
    }
}

UIBezierPath的roundedRect存在奇怪的间隙。

英文:

I need to draw a rounded rect. However, at very special corner radius values (between 34 to 37), it causes very strange bugs like the image below. Can someone explain to me why it happened?

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        drawView()
        self.view.backgroundColor = .red
    }

    func drawView() {
        let rect = CGRect(x: 100, y: 100, width: 200, height: 100)
        let borderWidth = 10.0
        let cornerRadius = 34.0
        
        
        let layer = CAShapeLayer()
        layer.strokeColor = UIColor.green.cgColor
        layer.lineWidth = borderWidth
        layer.fillColor = UIColor.white.cgColor
        
        let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
        
        
        layer.path = path.cgPath
        
        self.view.layer.addSublayer(layer)
        
    }
}


UIBezierPath的roundedRect存在奇怪的间隙。

答案1

得分: 2

I suspect that a rounded rectangle is implemented by joining some curves together and the artifact that you are seeing is caused by the lineJoin property of the layer.

Setting lineJoin to .round fixes it for me:

layer.lineJoin = .round
英文:

I suspect that a rounded rectangle is implemented by joining some curves together and the artifact that you are seeing is caused by the lineJoin property of the layer.

Setting lineJoin to .round fixes it for me:

layer.lineJoin = .round

UIBezierPath的roundedRect存在奇怪的间隙。

答案2

得分: 0

使用2个贝塞尔路径并填充颜色,而不是使用单个路径描边。

问题是CALayer使用多个路径创建边框,导致路径重叠,然后与填充规则evenOdd混合,导致奇怪的行为。这也使得创建完美圆形变得不可能。

这篇文章解释了为什么会发生这种情况。

感谢Zalo iOS VietNam团队帮助我理解这个问题。

我的解决方案是通过使用2个分开的路径并在它们之间填充颜色来避免重叠。

另一种修复方法是使用CGMutablePath。

func draw() {
    let rect = CGRect(x: 30, y: 50, width: 200, height: 100)
    let borderWidth: CGFloat = 5
    let cornerRadius: CGFloat = 5
    
    let outerPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
    
    let innerRect = CGRect(x: rect.minX + borderWidth, y: rect.minY + borderWidth, width: rect.width - borderWidth * 2, height: rect.height - borderWidth * 2)
    let innerPath = UIBezierPath(roundedRect: innerRect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
    
    let path = UIBezierPath()
    path.append(outerPath)
    path.append(innerPath)
    
    let layer = CAShapeLayer()
    layer.fillColor = UIColor.red.cgColor
    layer.fillRule = .evenOdd
    layer.path = path.cgPath
    
    self.view.layer.addSublayer(layer)
}
英文:

Using 2 bezierpath and fill with color instead of using single path with stroke.

The problem is CALayer using multiple path to create a border, cause overlap between the path then it mixed with fill rule .evenOdd cause weird behavior.
This also make impossible to create a perfect circle.

This article explained why is it happened.

https://www.paintcodeapp.com/blogpost/code-for-ios-7-rounded-rectangles

Thanks Zalo iOS VietNam team to help me understand this.

My solution to avoid overlap by using 2 separated paths and fill color between them.

The another way to fix is using CGMutablePath.

 func draw() {
        let rect = CGRect(x: 30, y: 50, width: 200, height: 100)
        let boderWidth: CGFloat = 5
        let cornerRadius: CGFloat = 5
        
        
        
        let outterPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
        
        let innerRect = CGRect(x: rect.minX + boderWidth, y: rect.minY + boderWidth, width: rect.width - boderWidth * 2, height: rect.height - boderWidth * 2)
        let innerPath = UIBezierPath(roundedRect: innerRect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
        
        let path = UIBezierPath()
        path.append(outterPath)
        path.append(innerPath)
        
        let layer = CAShapeLayer()
        layer.fillColor = UIColor.red.cgColor
        layer.fillRule = .evenOdd
        layer.path = path.cgPath
        
        self.view.layer.addSublayer(layer)
    }

huangapple
  • 本文由 发表于 2023年5月10日 11:30:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76214705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定