swift UIBezierPath圆角变为圆形

sg3maiej  于 2022-12-02  发布在  Swift
关注(0)|答案(2)|浏览(166)

我遇到了一个奇怪的问题。我不知道是我犯了什么错误,还是UIBezierPath有问题。
我想让UIBezierPath的圆角半径大约为宽度或高度的40%,但问题是只要我增加0.1%的圆角半径,它就会变成圆形。例如,它显示圆角半径为0.327%,但只要我将其设置为0.328%,它就会变成圆形。
请让我知道我可以做些什么来解决我的问题。Current scenario with corner percentage
类对于我的看法如下。

class MyView: UIView {
    var fraction : CGFloat = 0.5 {
        didSet {
            progressBorder.strokeEnd = fraction
        }
    }
    
    var strokeWidth : CGFloat = 4.0 {
        didSet {
            
        }
    }
    @IBInspectable var cornerPercentage : CGFloat = 0.327
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        layer.cornerRadius = frame.height * cornerPercentage
//        backgroundColor = .red
    }
    
    let progressBorder = CAShapeLayer()
    
    
    override func draw(_ rect: CGRect) {

        let cornerrad : CGFloat = (frame.height) * cornerPercentage
        layer.borderColor = UIColor.systemPink.cgColor
        
        layer.cornerRadius = cornerrad
        let border = CAShapeLayer()
        // make sure this path coincides with the border of the view
        border.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerrad).cgPath
        border.cornerRadius = cornerrad
        border.strokeStart = 0
        border.strokeEnd = 1
        border.strokeColor = AppColor.fieldsBackground().cgColor
        border.lineWidth = strokeWidth
        border.fillColor = nil
        
        // make sure this path coincides with the border of the view
        progressBorder.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerrad).cgPath
        progressBorder.cornerRadius = cornerrad
        progressBorder.lineJoin = .miter
        progressBorder.lineCap = .round
        progressBorder.strokeStart = 0
        progressBorder.strokeEnd = fraction
        
        progressBorder.strokeColor = AppColor.buttonsPrimary().cgColor
        progressBorder.lineWidth = strokeWidth
        progressBorder.fillColor = nil
        layer.addSublayer(border)
        layer.addSublayer(progressBorder)
        backgroundColor = .white
    }
}

我需要一个高度或宽度为正方形视图40%的圆角进度视图

5m1hhzi4

5m1hhzi41#

上面的答案适用于圆角半径。但现在我希望进度是从确切的中心开始。目前它是从远离中心的一点开始。
Example
图像中的进度strokeEnd为0.5。
我想要类似this的东西

xwbd5t1u

xwbd5t1u2#

如果你跟随我评论中的链接,你会看到关于UIBezierPath(roundedRect: ...)中“bug”的讨论。
下面是MyView的修改版本--带有cornerPercentage = 0.4--它避免了这个bug:

class MyView: UIView {
    var fraction : CGFloat = 0.5 {
        didSet {
            progressBorder.strokeEnd = fraction
        }
    }
    
    var strokeWidth : CGFloat = 4.0 {
        didSet {
            border.lineWidth = strokeWidth
            progressBorder.lineWidth = strokeWidth
        }
    }
    @IBInspectable var cornerPercentage : CGFloat = 0.4 // 0.327
    
    let border = CAShapeLayer()
    let progressBorder = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        layer.addSublayer(border)
        layer.addSublayer(progressBorder)

        border.lineWidth = strokeWidth
        progressBorder.lineWidth = strokeWidth

        border.fillColor = nil
        progressBorder.fillColor = nil

        layer.borderColor = UIColor.systemPink.cgColor
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let cornerrad : CGFloat = (bounds.height) * cornerPercentage
        
        layer.cornerRadius = cornerrad
        
        let r: CGRect = bounds
        
        // center points for the corner arcs
        let ptCTR: CGPoint = CGPoint(x: r.maxX - cornerrad, y: r.minY + cornerrad)
        let ptCBR: CGPoint = CGPoint(x: r.maxX - cornerrad, y: r.maxY - cornerrad)
        let ptCBL: CGPoint = CGPoint(x: r.minX + cornerrad, y: r.maxY - cornerrad)
        let ptCTL: CGPoint = CGPoint(x: r.minX + cornerrad, y: r.minY + cornerrad)
        
        let bez: UIBezierPath = UIBezierPath()
        
        // want to start the path at top-center
        bez.move(to: CGPoint(x: r.midX, y: r.minY))
    
        // Top-Right corner
        bez.addArc(withCenter: ptCTR, radius: cornerrad, startAngle: .pi * 1.5, endAngle: .pi * 0.0, clockwise: true)
        
        // Bottom-Right corner
        bez.addArc(withCenter: ptCBR, radius: cornerrad, startAngle: .pi * 0.0, endAngle: .pi * 0.5, clockwise: true)
        
        // Bottom-Left corner
        bez.addArc(withCenter: ptCBL, radius: cornerrad, startAngle: .pi * 0.5, endAngle: .pi * 1.0, clockwise: true)
        
        // Top-Left corner
        bez.addArc(withCenter: ptCTL, radius: cornerrad, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)
        
        // close the path
        bez.close()
        
        // make sure this path coincides with the border of the view
        border.path = bez.cgPath
        border.strokeStart = 0
        border.strokeEnd = 1
        border.strokeColor = UIColor.lightGray.cgColor // AppColor.fieldsBackground().cgColor
        
        // make sure this path coincides with the border of the view
        progressBorder.path = bez.cgPath
        progressBorder.strokeStart = 0
        progressBorder.strokeEnd = fraction
        
        progressBorder.strokeColor = UIColor.systemBlue.cgColor // AppColor.buttonsPrimary().cgColor
    }
}

以及示例视图控制器-fraction0.1开始,并且随着每次敲击增加0.1

class ViewController: UIViewController {
    
    let myTestView = MyView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        myTestView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(myTestView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            myTestView.centerXAnchor.constraint(equalTo: g.centerXAnchor, constant: 0.0),
            myTestView.centerYAnchor.constraint(equalTo: g.centerYAnchor, constant: 0.0),
            myTestView.widthAnchor.constraint(equalToConstant: 300.0),
            myTestView.heightAnchor.constraint(equalToConstant: 50.0),
            
        ])
        
        myTestView.fraction = 0.1

    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        myTestView.fraction += 0.1
    }
    
}

作为旁注:你会发现我稍微移动了一下代码。你可以添加形状层,并在init期间设置它们的不变属性,然后在layoutSubviews()中设置路径和其他可变属性。在draw()中添加子层不是一个好主意。

相关问题