2016-04-19 11 views
0

をアニメーションではありません。すべてが期待どおりに動作し、動作しますが、アニメーションを作成しようとすると、アニメーションではなく即座に変更が適用されます。どんな助けもありがとう。私はすべてのことは、アニメーション作品を作るために必要とされるべきであるactionForKey:でアニメーションを返し、それを理解し、私は何を取得したよう暗黙のアニメーションは、私は私がアニメーション化する円形のプログレスバーに取り組んでいます

@interface CircularProgressLayer : CALayer 

@property (nonatomic, assign) CGFloat progressDegrees; 
@property (nonatomic, assign) CGFloat trackWidth; 

@end 

@implementation CircularProgressLayer : CALayer 

@dynamic progressDegrees; 
@dynamic trackWidth; 

- (id)initWithLayer:(id)layer 
{ 
    if ((self = [super initWithLayer:layer])) 
    { 
     if ([layer isKindOfClass:[CircularProgressLayer class]]) 
     { 
      self.progressDegrees = ((CircularProgressLayer*)layer).progressDegrees; 
     } 
    } 

    return self; 
} 

// Instruct to Core Animation that a change in the custom property should automatically trigger a redraw of the layer. 
+ (BOOL)needsDisplayForKey:(NSString*)key 
{ 
    if ([key isEqualToString:@"progressDegrees"]) 
    { 
     return YES; 
    } 
    if ([key isEqualToString:@"trackWidth"]) 
    { 
     return YES; 
    } 

    return [super needsDisplayForKey:key]; 
} 

// Needed to support implicit animation of this property. 
// Return the basic animation the implicit animation will leverage. 
- (id<CAAction>)actionForKey:(NSString *)key 
{ 
    if ([key isEqualToString:@"progressDegrees"]) 
    { 
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key]; 
     animation.fromValue = [[self presentationLayer] valueForKey:key]; 
     animation.duration = 5.0; 
     animation.fillMode = kCAFillModeForwards; 
     animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 

     return animation; 
    } 
    return [super actionForKey:key]; 
} 

は、ここに私の層です。私の図面のすべては、現在、私はそれをアニメーション化するために取得する層でそれを入れていた学んだ前に、それはのdrawRectコードとして始まり原因(この層を実装して私の見解のdrawLayer:inContext:方法に含まれている、と私は上のすべてを変換していません)しかし、私がアップルからダウンロードしたsample codeはこれがちょうどいいように見える。

-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context 
{ 
    UIGraphicsPushContext(context); 
    [self drawTrackInContext:context]; 
    [self drawProgressInContext:context]; 
    UIGraphicsPopContext(); 
} 

- (void)drawProgressInContext:(CGContextRef)context 
{  
    if (self.progress < 1) 
    { 
     // No progress, get out 
     return; 
    } 

    CGSize size = self.bounds.size; 

    FlipContextVertically(size); 
    CGContextSaveGState(context); 
    { 
     UIBezierPath *circle = [self circle]; 
     CGContextSetLineWidth(context, 0.0); 

     CGFloat degrees = 360.0; 

     for (int i = 0; i < degrees; i++) 
     { 
      if (i > ((RMONCircularProgressLayer *)self.layer).progressDegrees) 
      { 
       break; 
      } 

      CGFloat theta = 2 * M_PI * (CGFloat) i/degrees; 
      CGFloat x = self.radius * sin(theta); 
      CGFloat y = self.radius * cos(theta); 

      MovePathCenterToPoint(circle, CGPointMake(x, y)); 
      OffsetPath(circle, CGSizeMake(size.width/2, size.height/2)); 

      CGContextSetFillColorWithColor(context, [self colorForDegree:i].CGColor); 
      CGContextAddPath(context, circle.CGPath); 
      CGContextDrawPath(context, kCGPathFillStroke); 
     } 
    } 
    CGContextRestoreGState(context); 
} 

- (void)drawTrackInContext:(CGContextRef)context 
{ 
    CGContextSaveGState(context); 
    { 
     // Draw the circle covering middle of the screen 
     CGSize size = self.bounds.size; 

     CGContextSetLineWidth(context, self.trackWidth); // will only be filled color 

     CGContextSetStrokeColorWithColor(context, self.trackColor.CGColor); 
     CGContextSetFillColorWithColor(context, self.fillColor.CGColor); 
     CGContextSetAlpha(context, 1.0); 

     CGContextAddArc(context, (CGFloat)size.width/2.0, (CGFloat)size.height/2.0, self.radius, 0, (CGFloat)M_PI*2.0, 1); 
     CGContextDrawPath(context, kCGPathFillStroke); 
    } 
    CGContextRestoreGState(context); 
} 

drawTrackInContextだけ進捗円が含まれる円を、描画します。ここで

は、描画コードがあります。 は私がアニメーション化する予定の描画コードです。 Erica SadunのiOS Drawingには、私が含まなかったコンテキストやパス操作を行うヘルパー関数がいくつかありますが、関数名はかなり自明です。

ご協力いただければ幸いです。

はFYI:私はそれが簡単だ場合は、この明示的なアニメーションを作るために喜んでより多くのですが、私はどちらかその作品を作ることができなかったので、この方向に行くことになりました。層プロパティはアニメーション化された場合

+0

'drawLayer:inContext:' –

+0

の中にコードを表示してください。なぜ描画コードを追加したのですか? –

答えて

2

は、そのプロパティの値は、中間値を表すために、経時的に変化しません。代わりに、レイヤー時間のその瞬間のプロパティの値はアクティブなアニメーションから導出され、レイヤーのpresentationLayerで使用可能になります。

アニメーションがアクティブである場合、drawInContext:は、プレゼンテーション層ではなく、主層の上に呼び出されます。同様に、-drawLayer:inContext:はメインレイヤではなくプレゼンテーションレイヤを受け取ります。

-drawProgressInContext:は、呼び出し元関数のレイヤーを使用せず、代わりにself.layer.progressDegreesを読み込み、値を取得します。これは常に割り当てられた値になります。あなたはif (self.progress < 1)に中止するときにも問題がある

- (void)drawProgressInLayer:(CALayer *)layer context:(CGContextRef)context 
{ 
    ... 
    if (i > ((RMONCircularProgressLayer *)layer).progressDegrees) { 
     ... 

:この修正は、その機能に層を渡し、値を読むことです。ゼロ以外の値から0になるとアニメーション化に失敗します。同じ修正が適用されます:if ((RMONCircularProgressLayer *)layer).progressDegrees < 1)

+0

詳細な説明をありがとうございます。私はアニメーションの作業を取得するために、プレゼンテーション層の値を利用渡って走ったが、私は2の間で変換する場合(isAnimating)ブロックを追加しなければならなかった、と私はそれが簡単であることを知っていました。私は描画コードが2つの異なるレイヤーで呼び出されたことに気付かなかった。驚くばかり。 –