2013-03-10 10 views
14

私はUIBezierPathをアニメーション化しようとしています。私はそれをしようとするためにCAShapeLayerをインストールしました。残念ながら、アニメーションは機能していないので、レイヤーが影響を受けているかどうかはわかりません(レイヤーを作成する前と同じことをコードが実行しているため)。私のUIBezierPathをCAShapeLayerでアニメーション化するには?

ここに実際のコードがあります。助けが大好きです。 Draw2Dは、UIViewControllerに埋め込まれたUIViewの実装です。すべての描画がDraw2Dクラス内で行われています。 [_helper createDrawing ...]を呼び出すと、単に_uipath変数にポイントが設定されます。私はそれがあることだとパスがアニメーションしない理由のための明白な理由は、おそらくあります知っている

// 
// Draw2D.m 
// Draw2D 
// 
// Created by Marina on 2/19/13. 
// Copyright (c) 2013 Marina. All rights reserved. 
// 

#import "Draw2D.h" 
#import"Draw2DHelper.h" 
#include <stdlib.h> 
#import "Foundation/Foundation.h" 
#import <QuartzCore/QuartzCore.h> 

int MAX_WIDTH; 
int MAX_HEIGHT; 

@implementation Draw2D 

- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 

     if (self.pathLayer != nil) { 
      [self.pathLayer removeFromSuperlayer]; 
      self.pathLayer = nil; 
     } 

     self.animationLayer = [CALayer layer]; 
     self.animationLayer.frame = self.bounds; 
     [self.layer addSublayer:self.animationLayer]; 

     CAShapeLayer *l_pathLayer = [CAShapeLayer layer]; 
     l_pathLayer.frame = self.frame; 
     l_pathLayer.bounds = self.bounds; 
     l_pathLayer.geometryFlipped = YES; 
     l_pathLayer.path = _uipath.CGPath; 
     l_pathLayer.strokeColor = [[UIColor grayColor] CGColor]; 
     l_pathLayer.fillColor = nil; 
     l_pathLayer.lineWidth = 1.5f; 
     l_pathLayer.lineJoin = kCALineJoinBevel; 

     [self.animationLayer addSublayer:l_pathLayer]; 
     self.pathLayer = l_pathLayer; 
     [self.layer addSublayer:l_pathLayer]; 
    } 
    return self; 
} 

// Only override drawRect: if you perform custom drawing. 
// An empty implementation adversely affects performance during animation. 
- (void)drawRect:(CGRect)rect :(int) points :(drawingTypes) type //:(Boolean) initial 
{ 
    //CGRect bounds = [[UIScreen mainScreen] bounds]; 
    CGRect appframe= [[UIScreen mainScreen] applicationFrame]; 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    _helper = [[Draw2DHelper alloc ] initWithBounds :appframe.size.width :appframe.size.height :type]; 

    CGPoint startPoint = [_helper generatePoint] ; 

    [_uipath moveToPoint:startPoint]; 
    [_uipath setLineWidth: 1.5]; 

    CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor); 

    CGPoint center = CGPointMake(self.center.y, self.center.x) ; 
    [_helper createDrawing :type :_uipath :((points>0) ? points : defaultPointCount) :center]; 
    self.pathLayer.path = (__bridge CGPathRef)(_uipath); 
    [_uipath stroke]; 

    [self startAnimation]; 
} 

- (void) startAnimation { 
    [self.pathLayer removeAllAnimations]; 

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    pathAnimation.duration = 3.0; 
    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 
    [self.pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"]; 

} 

- (void)drawRect:(CGRect)rect { 
    if (_uipath == NULL) 
     _uipath = [[UIBezierPath alloc] init]; 
    else 
     [_uipath removeAllPoints]; 

    [self drawRect:rect :self.graphPoints :self.drawingType ]; 
} 

- (void)refreshRect:(CGRect)rect { 
    [self setNeedsDisplay]; 
} 

@end 

:以下

#define defaultPointCount ((int) 25) 

@property Draw2DHelper *helper; 
@property drawingTypes drawingType; 
@property int graphPoints; 
@property UIBezierPath *uipath; 

@property CALayer *animationLayer; 
@property CAShapeLayer *pathLayer; 

- (void)refreshRect:(CGRect)rect; 

が実際の実装である:

Draw2D.hは、次のプロパティを定義します(今すぐ現れるものとは対照的に)絵を描いていますが、私はそれを見ていませんでした。

また、誰でもCAShapeLayersとアニメーションの基本的なプライマーをお勧めすることができます、私はそれを感謝します。十分に良いものを越えて来なかった。

ありがとうございます。

+0

アニメーションでは、私自身の説明をお勧めします。http://www.apeth.com/iOSBook/ch17.html私が他の場所で説明していないことを説明しています。 – matt

+0

ありがとう!それをチェックします – marina

答えて

40

drawRect(間接的に、少なくとも)以内でアニメーションを作成しようとしているようです。それは意味をなさない。 drawRect内にアニメーション化されません。 drawRectは、1つのフレームを描画するために使用されます。いくつかのアニメーションはタイマまたはCADisplayLinkで行われ、setNeedsDisplay(これはiOSがdrawRectと呼ぶことになります)を繰り返し呼び出すと、その時点でアニメーションの進行状況を示す単一のフレームを描画することがあります。しかし、あなたは単にdrawRectを単独でアニメーションを開始する必要はありません。

しかし、Core AnimationのCAShapeLayerCABasicAnimationを使用しているので、カスタムdrawRectはまったく必要ありません。 QuartzのCore Animationはあなたのためにすべてを処理します。例えば、ここでUIBezierPathの描画をアニメーション化するための私のコードは次のとおりです。私はアニメーションを描画を開始したいとき

#import <QuartzCore/QuartzCore.h> 

@interface View() 
@property (nonatomic, weak) CAShapeLayer *pathLayer; 
@end 

@implementation View 

/* 
// I'm not doing anything here, so I can comment this out 
- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 
    } 
    return self; 
} 
*/ 

/* 
// Only override drawRect: if you perform custom drawing. 
// An empty implementation adversely affects performance during animation. 
- (void)drawRect:(CGRect)rect 
{ 
    // Drawing code 
} 
*/ 

// It doesn't matter what my path is. I could make it anything I wanted. 

- (UIBezierPath *)samplePath 
{ 
    UIBezierPath *path = [UIBezierPath bezierPath]; 

    // build the path here 

    return path; 
} 

- (void)startAnimation 
{ 
    if (self.pathLayer == nil) 
    { 
     CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 

     shapeLayer.path = [[self samplePath] CGPath]; 
     shapeLayer.strokeColor = [[UIColor grayColor] CGColor]; 
     shapeLayer.fillColor = nil; 
     shapeLayer.lineWidth = 1.5f; 
     shapeLayer.lineJoin = kCALineJoinBevel; 

     [self.layer addSublayer:shapeLayer]; 

     self.pathLayer = shapeLayer; 
    } 

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    pathAnimation.duration = 3.0; 
    pathAnimation.fromValue = @(0.0f); 
    pathAnimation.toValue = @(1.0f); 
    [self.pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"]; 
} 

@end 

その後、私はちょうど私のstartAnimationメソッドを呼び出します。私は実際にUIViewの動作を変更していないので、おそらくUIViewというサブクラスがこれほど単純なものでは必要ないでしょう。あなたはUIViewのカスタムサブクラスdrawRectをサブクラス化していることは間違いありませんが、ここでは必要ありません。

あなたはいくつかの参照を求めた:あなたはそれを見ていない場合、私はおそらく、AppleのCore Animation Programming Guideのレビューに開始する

  • 私にとっては、Mike Nachbaur's Core Animation Tutorial Part 4に行ったときにすべてが落ちて、デモを最初から再生していました。明らかに、パート1からパート3もチェックアウトできます。
+0

ありがとうございます。シーン1(ライン、ベジエ、フラクタルなど)で作成される描画の種類を入力とし、シーン2では描画を生成するアプリケーションです。 Scene2 View Controllerには、上に2つのボタンがあります.1つはリフレッシュ用です。同じ種類の新しい図面がページ上に生成されます。戻るボタンはシーン1に戻り、新しいパラメータを入力します。また、実際の図面が下に表示されているUIViewもあります。コードは元の投稿に囲まれています。このすべてを知って、あなたはまだ私はUIViewとは対照的にビューで行くことをお勧めしますか? – marina

+0

@marina私の 'View'クラスは実際に' UIView'サブクラスなので、私はあなたの "UIView'とは逆の質問を理解していません。私の主なポイントは、Core Animationの 'CAShapeLayer'を使用する際にカスタムの' drawRect'コードを行う必要がないことでした。 'drawRect'をタイマーで、' CADisplayLink'を 'UIView'サブクラスで(少し複雑です)、またはCore Animationを使用してアニメーションすることができます。 'CAShapeLayer'を使うときは、' UIViewController'サブクラスで行います( 'drawRect'の代替と混同しないように)。しかし、それは' UIView'と 'UIViewController'の両方のサブクラスで動作するので個人的な好みです。 – Rob

+0

要するに、あなたの 'UIView'サブクラスで' CAShapeLayer'コードを実行することは間違いありません(私の例では示しています)。私の主なポイントは、 'CAShapeLayer'を使用するときにカスタムの' drawRect'コードは必要ないということです。 – Rob

関連する問題