简体   繁体   中英

animating circular UIBezierPath without rounding the stroke

I'm trying to add an animation to my UIBezierPath , but I want to keep the hard edges my current fillPath is creating, here's a screenshot of what the result should look like:

在此处输入图片说明

I did manage to get one animation working correctly using a slightly modified version of this code:

// create an object that represents how the curve 

// should be presented on the screen

let progressLine = CAShapeLayer()
progressLine.path = ovalPath.CGPath
progressLine.strokeColor = UIColor.blueColor().CGColor
progressLine.fillColor = UIColor.clearColor().CGColor
progressLine.lineWidth = 10.0
progressLine.lineCap = kCALineCapRound

// add the curve to the screen
self.view.layer.addSublayer(progressLine)

// create a basic animation that animates the value 'strokeEnd'
// from 0.0 to 1.0 over 3.0 seconds
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.duration = 3.0
animateStrokeEnd.fromValue = 0.0
animateStrokeEnd.toValue = 1.0

// add the animation
progressLine.addAnimation(animateStrokeEnd, forKey: "animate stroke end animation")

The above code is from: http://mathewsanders.com/animations-in-swift-part-two/

It did work, but the stroke it created was rounded.

The only examples/tutorials and other questions I could find on this matter, was using CAShapes. I'm currently not using CAShapes or layers. (I don't know if that's needed to make an animation work with this, but I figure I'd ask)

Here's my current code (without any animation). To draw my little circle chart.

class CircleChart: UIView {

var percentFill: Float = 99.00 {
    didSet {
        // Double check that it's less or equal to 100 %
        if percentFill <=  maxPercent {
            //the view needs to be refreshed
            setNeedsDisplay()
        }
    }
}

var fillColor: UIColor = UIColor.formulaBlueColor()
var chartColor: UIColor = UIColor.formulaLightGrayColor()

override func drawRect(rect: CGRect) {
    // Define the center.
    let center = CGPoint(x:bounds.width/2, y: bounds.height/2)

    // Define the radius
    let radius: CGFloat = max(bounds.width, bounds.height)

    // Define the width of the circle
    let arcWidth: CGFloat = 10

    // Define starting and ending angles (currently unused)
    let startAngle: CGFloat = degreesToRadians(-90)
    let endAngle: CGFloat = degreesToRadians(270)

    // 5
    var path = UIBezierPath(arcCenter: center,
        radius: bounds.width/2 - arcWidth/2,
        startAngle: startAngle,
        endAngle: endAngle,
        clockwise: true)

    // 6
    path.lineWidth = arcWidth
    chartColor.setStroke()
    path.stroke()

    //Draw the fill-part

    //calculate the arc for each per percent
    let arcLengthPerPercent = degreesToRadians(360/100)

    //then multiply out by the actual percent
    let fillEndAngle = arcLengthPerPercent * CGFloat(percentFill) + startAngle


    //2 - draw the outer arc
    var fillPath = UIBezierPath(arcCenter: center,
        radius: bounds.width/2 - arcWidth/2,
        startAngle: startAngle,
        endAngle: fillEndAngle,
        clockwise: true)

    //3 - draw the inner arc
    fillPath.addArcWithCenter(center,
        radius: bounds.width/2 - arcWidth/2,
        startAngle: fillEndAngle,
        endAngle: startAngle,
        clockwise: false)

    //4 - close the path
    fillPath.closePath()

    fillColor.setStroke()
    fillPath.lineWidth = arcWidth
    fillPath.stroke()
}
}

What would be the best way to animate the fillPath? Or do I need to redo everything in CAShapes and layers, to make it work?

Any help would be greatly appreciated.

If you want it square, why are you using progressLine.lineCap = kCALineCapRound ? Just delete that line, and you'll get the default butt end ( kCALineCapButt ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM