7

私が取り組んでいる CALayer サブクラスには、自動的にアニメーション化したいカスタム プロパティがあります。つまり、プロパティが「myProperty」と呼ばれると仮定すると、次のコードが必要です。

[myLayer setMyProperty:newValue];

現在の値から「newValue」へのスムーズなアニメーションを発生させます。

actionForKey: と needsDisplayForKey: (次のコードを参照) をオーバーライドするアプローチを使用して、古い値と新しい値の間を単純に補間するだけで、非常にうまく動作させることができました。

私の問題は、プロパティの現在の値と新しい値の両方に応じて、わずかに異なるアニメーションの継続時間またはパス (または何でも) を使用したいことであり、actionForKey 内から新しい値を取得する方法を理解できませんでした。 :

前もって感謝します

@interface ERAnimatablePropertyLayer : CALayer {
    float myProperty;
}
@property (nonatomic, assign) float myProperty;
@end
@implementation ERAnimatablePropertyLayer
@dynamic myProperty;

- (void)drawInContext:(CGContextRef)ctx {
     ... some custom drawing code based on "myProperty"
}

- (id <CAAction>)actionForKey:(NSString *)key {
    if ([key isEqualToString:@"myProperty"]) {
        CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:key];
        theAnimation.fromValue = [[self presentationLayer] valueForKey:key];

        ... I want to do something special here, depending on both from and to values...


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

+ (BOOL)needsDisplayForKey:(NSString *)key {
    if ([key isEqualToString:@"myProperty"])
        return YES;
    return [super needsDisplayForKey:key];
    }
    @end
4

3 に答える 3

2

actionForKey:プロパティ値を更新する前にCore Animation を呼び出します。プロパティ値を送信して更新した後、アクションを実行しますrunActionForKey:object:arguments:。呼び出しのみのCAAnimation実装。runActionForKey:object:arguments:[object addAnimation:self forKey:key]

からアニメーションを返す代わりに、実行時にアニメーションを作成してインストールする をactionForKey:返すことができます。CAActionこのようなもの:

@interface MyAction: NSObject <CAAction>
@property (nonatomic, strong) id priorValue;
@end

@implementation MyAction

- (void)runActionForKey:(NSString *)key object:(id)anObject arguments:(NSDictionary *)dict {
    ERAnimatablePropertyLayer *layer = anObject;
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
    id newValue = [layer valueForKey:key];
    // Set up animation using self.priorValue and newValue to determine
    // fromValue and toValue. You could use a CAKeyframeAnimation instead of
    // a CABasicAnimation.
    [layer addAnimation:animation forKey:key];
}

@end

@implementation ERAnimatablePropertyLayer

- (id <CAAction>)actionForKey:(NSString *)key {
    if ([key isEqualToString:@"myProperty"]) {
        MyAction *action = [[MyAction alloc] init];
        action.priorValue = [self valueForKey:key];
        return action;
    }
    return [super actionForKey:key];
}

この回答cornerRadiusでは、同様の手法 (Swift のアニメーション化)の実例を見つけることができます。

于 2016-03-01T04:53:57.080 に答える
1

古い値と新しい値を CATransaction に格納できます。

-(void)setMyProperty:(float)value
{
    NSNumber *fromValue = [NSNumber numberWithFloat:myProperty];
    [CATransaction setValue:fromValue forKey:@"myPropertyFromValue"];

    myProperty = value;

    NSNumber *toValue = [NSNumber numberWithFloat:myProperty];
    [CATransaction setValue:toValue forKey:@"myPropertyToValue"];
}

- (id <CAAction>)actionForKey:(NSString *)key {
    if ([key isEqualToString:@"myProperty"]) {
        CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:key];
        theAnimation.fromValue = [[self presentationLayer] valueForKey:key];
        theAnimation.toValue = [CATransaction objectForKey:@"myPropertyToValue"];

        // here you do something special.
    }

    return [super actionForKey:key];
}
于 2012-06-05T18:01:04.027 に答える