1. ホーム
  2. swift

[解決済み] アニメーションによる円の描画

2022-09-28 16:40:56

質問

円の描画をアニメーション化する方法を探しています。円を作成することはできましたが、まとめて描画してしまいます。

以下は、私の CircleView クラスです。

import UIKit

class CircleView: UIView {
  override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()
  }

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }


  override func drawRect(rect: CGRect) {
    // Get the Graphics Context
    var context = UIGraphicsGetCurrentContext();

    // Set the circle outerline-width
    CGContextSetLineWidth(context, 5.0);

    // Set the circle outerline-colour
    UIColor.redColor().set()

    // Create Circle
    CGContextAddArc(context, (frame.size.width)/2, frame.size.height/2, (frame.size.width - 10)/2, 0.0, CGFloat(M_PI * 2.0), 1)

    // Draw
    CGContextStrokePath(context);
  }
}

そして、ビューコントローラーのビュー階層に追加する方法は以下の通りです。

func addCircleView() {
    let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
    var circleWidth = CGFloat(200)
    var circleHeight = circleWidth
    // Create a new CircleView
    var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))

    view.addSubview(circleView)
}

円の描画を1秒かけてアニメーションさせる方法はありますか?

例)アニメーションの途中で、この画像の青い線のような感じになります。

どのように解決するのですか?

最も簡単な方法は、コアアニメーションの力を使って作業のほとんどを代行させることです。これを行うには、円を描くコードを drawRect 関数から CAShapeLayer . 次に CABasicAnimation をアニメーション化するために CAShapeLayer 's strokeEnd からのプロパティ 0.0 から 1.0 . strokeEnd はこのマジックの大きな部分を占めています; docs から。

strokeStart プロパティと組み合わせて、このプロパティはストロークするパスの このプロパティは、ストロークするパスのサブ領域を定義します。このプロパティの値は このプロパティの値は、ストロークを終了するパスに沿った相対的なポイントを示し、strokeStartプロパティは開始ポイントを定義します。 strokeStart プロパティは開始点を定義する。0.0を指定すると の値はパスの始点を表し、1.0 の値はパスの終点を表す。 はパスの終点を表す。その間の値は、パスの長さに沿って直線的に解釈される。 パスの長さに沿って線形に解釈されます。

もし strokeEnd0.0 に設定すると、何も描画されません。もし、これを 1.0 に設定すると、完全な円が描かれる。もし、これを 0.5 とすれば、半円が描かれます。

では、手始めに CAShapeLayer の中に CircleView 's init 関数に追加し、そのレイヤーをビューの sublayers に追加します (また、必ず drawRect 関数を削除してください)。

let circleLayer: CAShapeLayer!

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()
    
    // Use UIBezierPath as an easy way to create the CGPath for the layer.
    // The path should be the entire circle.
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(Double.pi * 2.0), clockwise: true)
    
    // Setup the CAShapeLayer with the path, colors, and line width
    circleLayer = CAShapeLayer()
    circleLayer.path = circlePath.CGPath
    circleLayer.fillColor = UIColor.clearColor().CGColor
    circleLayer.strokeColor = UIColor.redColor().CGColor
    circleLayer.lineWidth = 5.0;
    
    // Don't draw the circle initially
    circleLayer.strokeEnd = 0.0
    
    // Add the circleLayer to the view's layer's sublayers
    layer.addSublayer(circleLayer)
}

注意 を設定しています。 circleLayer.strokeEnd = 0.0 を設定し、円がすぐに描画されないようにしています。

さて、円のアニメーションをトリガーするために呼び出すことができる関数を追加しましょう。

func animateCircle(duration: NSTimeInterval) {
    // We want to animate the strokeEnd property of the circleLayer
    let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))

    // Set the animation duration appropriately
    animation.duration = duration

    // Animate from 0 (no circle) to 1 (full circle)
    animation.fromValue = 0
    animation.toValue = 1

    // Do a linear animation (i.e. the speed of the animation stays the same)
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)

    // Set the circleLayer's strokeEnd property to 1.0 now so that it's the
    // right value when the animation ends.
    circleLayer.strokeEnd = 1.0

    // Do the actual animation
    circleLayer.add(animation, forKey: "animateCircle")
}

そして、あとはあなたの addCircleView を追加したときにアニメーションを開始するようにします。 CircleView をその superview :

func addCircleView() {
    let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
     var circleWidth = CGFloat(200)
     var circleHeight = circleWidth

        // Create a new CircleView
     var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))

     view.addSubview(circleView)

     // Animate the drawing of the circle over the course of 1 second
     circleView.animateCircle(1.0)
}

全部合わせるとこんな感じになるはずです。

注意 このように繰り返されるのではなく、アニメートした後、一周したままになります。