Swift: 如何一步步画圆?
Swift: How to draw a circle step by step?
我建一个工程,最初是画一个圆弧,这个圆弧是圆的1/8。
然后我在 viewController 上放了一个按钮,每当我点击这个按钮时,它会在上面无缝绘制另一个 1/8 的圆。
但是我遇到了一个问题:当我点击按钮时,它几乎快速绘制了弧线(0.25s),而不是我之前设置的持续时间(1s)。
如何实现无论我什么时候点击按钮,它消耗的时间都与我之前设置的持续时间相同?
import UIKit
let π = CGFloat(M_PI)
class ViewController: UIViewController {
var i: CGFloat = 1
var maxStep: CGFloat = 8
var circleLayer: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
let startAngle = CGFloat(0)
let endAngle = 2*π
let ovalRect = CGRectMake(100, 100, 100, 100)
let ovalPath = UIBezierPath(arcCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)), radius: CGRectGetWidth(ovalRect), startAngle: startAngle, endAngle: endAngle, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = ovalPath.CGPath
circleLayer.strokeColor = UIColor.blueColor().CGColor
circleLayer.fillColor = UIColor.clearColor().CGColor
circleLayer.lineWidth = 10.0
circleLayer.lineCap = kCALineCapRound
self.circleLayer = circleLayer
self.view.layer.addSublayer(self.circleLayer)
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1.0
anim.fromValue = 0.0
anim.toValue = self.i/self.maxStep
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
self.i++
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// when this action be triggered, it almost draws the arc rapidly, why?
@IBAction func buttonAnimate(sender: UIButton) {
if self.i<=self.maxStep {
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.i++
}
}
}
获取您的 animation
并重置属性。请参阅下面的代码:
@IBAction func buttonAnimate(sender: UIButton) {
if self.i<=self.maxStep {
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.circleLayer?.animationKeys()
let anim = self.circleLayer?.animationForKey("arc animation") as? CABasicAnimation
if anim == nil {
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1
anim.fromValue = (self.i - 1)/self.maxStep
anim.toValue = self.i/self.maxStep
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
}
self.i++
}
}
希望对您有所帮助!
这是正确的解决方案:
import UIKit
import UIKit
let π = CGFloat(M_PI)
class ViewController: UIViewController {
var i: CGFloat = 1
var maxStep: CGFloat = 8
var prevValue : CGFloat = 0.0
var circleLayer: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
let startAngle = CGFloat(0)
let endAngle = 2*π
let ovalRect = CGRectMake(100, 100, 100, 100)
let ovalPath = UIBezierPath(arcCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)), radius: CGRectGetWidth(ovalRect), startAngle: startAngle, endAngle: endAngle, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = ovalPath.CGPath
circleLayer.strokeColor = UIColor.blueColor().CGColor
circleLayer.fillColor = nil //UIColor.clearColor().CGColor
circleLayer.lineWidth = 10.0
circleLayer.lineCap = kCALineCapRound
self.circleLayer = circleLayer
self.view.layer.addSublayer(self.circleLayer!)
self.circleLayer!.strokeStart = 0.0
//Initial stroke-
setStrokeEndForLayer(self.circleLayer!, from: 0.0, to: self.i / self.maxStep, animated: true)
self.i++
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func buttonAnimate(sender: UIButton) {
if self.i <= self.maxStep {
setStrokeEndForLayer(self.circleLayer!, from: (self.i - 1 ) / self.maxStep, to: self.i / self.maxStep, animated: true)
self.i++
}
}
func setStrokeEndForLayer(layer: CALayer, var from:CGFloat, to: CGFloat, animated: Bool)
{
self.circleLayer!.strokeEnd = to
if animated
{
//Check if there is any existing animation is in progress, if so override, the from value
if let circlePresentationLayer = self.circleLayer!.presentationLayer()
{
from = circlePresentationLayer.strokeEnd
}
//Remove any on going animation
if (self.circleLayer?.animationForKey("arc animation") as? CABasicAnimation != nil)
{
//Remove the current animation
self.circleLayer!.removeAnimationForKey("arc animation")
}
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1
anim.fromValue = from
anim.toValue = to
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
}
}
}
我建一个工程,最初是画一个圆弧,这个圆弧是圆的1/8。
然后我在 viewController 上放了一个按钮,每当我点击这个按钮时,它会在上面无缝绘制另一个 1/8 的圆。
但是我遇到了一个问题:当我点击按钮时,它几乎快速绘制了弧线(0.25s),而不是我之前设置的持续时间(1s)。
如何实现无论我什么时候点击按钮,它消耗的时间都与我之前设置的持续时间相同?
import UIKit
let π = CGFloat(M_PI)
class ViewController: UIViewController {
var i: CGFloat = 1
var maxStep: CGFloat = 8
var circleLayer: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
let startAngle = CGFloat(0)
let endAngle = 2*π
let ovalRect = CGRectMake(100, 100, 100, 100)
let ovalPath = UIBezierPath(arcCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)), radius: CGRectGetWidth(ovalRect), startAngle: startAngle, endAngle: endAngle, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = ovalPath.CGPath
circleLayer.strokeColor = UIColor.blueColor().CGColor
circleLayer.fillColor = UIColor.clearColor().CGColor
circleLayer.lineWidth = 10.0
circleLayer.lineCap = kCALineCapRound
self.circleLayer = circleLayer
self.view.layer.addSublayer(self.circleLayer)
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1.0
anim.fromValue = 0.0
anim.toValue = self.i/self.maxStep
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
self.i++
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// when this action be triggered, it almost draws the arc rapidly, why?
@IBAction func buttonAnimate(sender: UIButton) {
if self.i<=self.maxStep {
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.i++
}
}
}
获取您的 animation
并重置属性。请参阅下面的代码:
@IBAction func buttonAnimate(sender: UIButton) {
if self.i<=self.maxStep {
self.circleLayer!.strokeStart = 0.0
self.circleLayer!.strokeEnd = self.i/self.maxStep
self.circleLayer?.animationKeys()
let anim = self.circleLayer?.animationForKey("arc animation") as? CABasicAnimation
if anim == nil {
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1
anim.fromValue = (self.i - 1)/self.maxStep
anim.toValue = self.i/self.maxStep
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
}
self.i++
}
}
希望对您有所帮助!
这是正确的解决方案:
import UIKit
import UIKit
let π = CGFloat(M_PI)
class ViewController: UIViewController {
var i: CGFloat = 1
var maxStep: CGFloat = 8
var prevValue : CGFloat = 0.0
var circleLayer: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
let startAngle = CGFloat(0)
let endAngle = 2*π
let ovalRect = CGRectMake(100, 100, 100, 100)
let ovalPath = UIBezierPath(arcCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)), radius: CGRectGetWidth(ovalRect), startAngle: startAngle, endAngle: endAngle, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = ovalPath.CGPath
circleLayer.strokeColor = UIColor.blueColor().CGColor
circleLayer.fillColor = nil //UIColor.clearColor().CGColor
circleLayer.lineWidth = 10.0
circleLayer.lineCap = kCALineCapRound
self.circleLayer = circleLayer
self.view.layer.addSublayer(self.circleLayer!)
self.circleLayer!.strokeStart = 0.0
//Initial stroke-
setStrokeEndForLayer(self.circleLayer!, from: 0.0, to: self.i / self.maxStep, animated: true)
self.i++
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func buttonAnimate(sender: UIButton) {
if self.i <= self.maxStep {
setStrokeEndForLayer(self.circleLayer!, from: (self.i - 1 ) / self.maxStep, to: self.i / self.maxStep, animated: true)
self.i++
}
}
func setStrokeEndForLayer(layer: CALayer, var from:CGFloat, to: CGFloat, animated: Bool)
{
self.circleLayer!.strokeEnd = to
if animated
{
//Check if there is any existing animation is in progress, if so override, the from value
if let circlePresentationLayer = self.circleLayer!.presentationLayer()
{
from = circlePresentationLayer.strokeEnd
}
//Remove any on going animation
if (self.circleLayer?.animationForKey("arc animation") as? CABasicAnimation != nil)
{
//Remove the current animation
self.circleLayer!.removeAnimationForKey("arc animation")
}
let anim = CABasicAnimation(keyPath: "strokeEnd")
// here i set the duration
anim.duration = 1
anim.fromValue = from
anim.toValue = to
self.circleLayer!.addAnimation(anim, forKey: "arc animation")
}
}
}