17

設定された進行状況に基づいて UIBezierPath をアニメーション化するプロジェクトがあります。BezierPath は円の形をしており、UIView にあり、アニメーションは現在 CADisplayLink を使用して drawRect で行われています。簡単に言えば、設定の進行状況に基づいてx、パスは放射状に拡張 (x以前よりも大きい場合) または縮小 (x小さい場合) する必要があります。

self.drawProgress = (self.displayLink.timestamp - self.startTime)/DURATION;

CGFloat startAngle = -(float)M_PI_2;
CGFloat stopAngle = ((self.x * 2*(float)M_PI) + startAngle);
CGFloat currentEndAngle = ((self.oldX * 2*(float)M_PI) + startAngle);
CGFloat endAngle = currentEndAngle-((currentEndAngle-stopAngle)*drawProgress);

UIBezierPath *guideCirclePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];

これは、x前回の更新以降に縮小した場合です。私が経験している問題は、実際にはいくつかあります。

  1. 形状は常に45 度から描画を開始します (ビューを回転させない限り)。これを変更する方法が見つかりませんstartAngleでした。-45º に設定しても、常に 45 に「ポップ」されるため、実際には違いはありません。
  2. これらのものをアニメーション化する他の方法はありますか? 私は使用について多くのことを読みましたCAShapeLayerが、これら 2 つの方法を使用する場合の実際の違い (欠点と利点の点で) をよく理解していません。誰かが明確にすることができれば、私は非常に義務付けられます!

更新:代わりにコードを CAShapeLayer に移行しましたが、別の問題に直面しています。この画像で最もよく説明されています:

ここに画像の説明を入力

何が起こっているかというと、レイヤーが縮小するはずのときに、薄い外側の線がまだそこにあるということです (移動の方向に関係なく)。バーが縮小しても、1- のデルタは、そのx上に新しい白い形状を明示的に作成しない限り削除されません。このコードは次のとおりです。何か案は?

UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:stopAngle clockwise:YES];
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [circlePath CGPath];
circle.strokeStart = 0;
circle.strokeEnd = 1.0*self.progress;

// Colour and other customizations here.

if (self.progress > self.oldProgress) {
    drawAnimation.fromValue = @(1.0*self.oldProgress);
    drawAnimation.toValue = @(circle.strokeEnd);
} else { 
    drawAnimation.fromValue = @(1.0*self.oldProgress);
    drawAnimation.toValue = @(1.0*self.progress);
    circle.strokeEnd = 1.0*self.progress;
}

drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; //kCAMediaTimingFunctionEaseIn
[circle addAnimation:drawAnimation forKey:@"strokeEnd"];

更新 2:他のバグのほとんどを解決しました。結局のところ、それは私がずっとばかげていて、アニメーション全体を過度に複雑にしていることが判明しました(言うまでもなく、どこでも1を掛けることは何ですか?)。解決できないバグの gif を作成しました。

ラジアルコントロールグリッチ

何か案は?

更新 3: (および閉鎖)。呼び出すことでバグを取り除くことができました

[self.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

そして今、すべてが正常に機能します。助けてくれてありがとう!

4

1 に答える 1

11

CAShapeLayer を使用すると、はるかに簡単でクリーンになります。その理由は、CAShapeLayer に strokeStart および strokeEnd プロパティが含まれているためです。これらの値の範囲は 0 (パスの開始) から 1 (パスの終了) で、アニメート可能です。

それらを変更することで、円の任意の弧 (または任意のパスの任意の部分) を簡単に描画できます。プロパティはアニメート可能であるため、拡大/縮小するパイのスライスまたはリング形状のセクションのアニメーションを作成できます。 . drawRect でコードを実装するよりもはるかに簡単で、パフォーマンスが向上します。

于 2013-11-21T21:56:37.487 に答える