Animation Types

3.1 Basic Animation

 

 CABasicAnimation

 

3.2 Keyframe Animations

 

我最近进行了一些关于关键桢动画方面的研究,感觉不错。关键桢动画其实是一个很酷的东西,因为它们会在你创建的层进行动作时给你提供更加精确的控制。基本动画在“开始”和“结束”点之间进行线性插值,在很多情况下,你都可以使用基本动画。但是有时候,如果你希望进行一些不一样或者更复杂的动画时,基本动画就不够用了。本文介绍的关键桢动画可以允许你在动画的过程中进行精确控制。


与基本动画进行线性插值不同,关键桢动画允许你在特定时间指定不同的数值,这样你可以在动画的全过程控制动画的展示和动作。


自从发明手绘电影以来,关键桢就在动画中起到了一定作用。一些资深的艺术家会针对一个场景画不同的关键桢,而一些刚入行的艺术家却会填满每一桢,以便使动画看起来更平滑。(有时候这个过程叫做tweening:两者之间的动画)。Core Animation的关键桢动画可以帮我们实现在关键桢之间的填充,我们只需要指定哪个是关键桢,系统会自动帮我们生成动画。


另外一个很酷的东西是,关键桢动画同样可以完成任何基本动画能够完成的动作。特别是点、大小或是矩形。比如如果我们希望让一个层的不透明度显示为一个动画,我们可以指定一些不同的数值(比如:0.25, 0.50, 0.75),然后在动画的过程的不同时间中逐渐变化。


再一个真的很酷的方面,我们不光可以使用离散数值,更可以使用CGPath去指定关键桢动画的值。换句话说,我们不仅仅可以在特定时间点指定特定的动画值,还可以使用曲线路径去指定动画的值。举例说明,我们可以将一个层的不透明度用钟型曲线表示:开始是透明,然后逐渐显现到某个特定透明度,再逐渐变为透明。我们还可以用CGPoint和CGSize值的路径做为动画的行进路线。这样,路径的x值可以表示横坐标也可以表示宽度,y既可以表示纵坐标还可以表示高度。

 

 

 

写道
Keyframes are specified by providing an array of values, one value for each specific keyframe we want to set during the animation.

 

写道
Another important thing to keep in mind about keyframe animations is that they work in terms of “normalized” time.

 

写道
Another important thing to keep in mind about keyframe animations is that they work in terms of “normalized” time.

 

The code to create the keyframe animation would look like this:

 

- (CAKeyframeAnimation *)opacityAnimation {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.values = [NSArray arrayWithObjects:
                                         [NSNumber numberWithFloat:0.0],
                                         [NSNumber numberWithFloat:0.75],
                                         [NSNumber numberWithFloat:0.0], nil];

animation.keyTimes = [NSArray arrayWithObjects:
                                           [NSNumber numberWithFloat:0.25],
                                           [NSNumber numberWithFloat:0.50],
                                           [NSNumber numberWithFloat:0.75], nil];
        return animation;
}

 

不设置keyTimes时的运行方式:

If we leave out setting the time values, the keyframe animation will just evenly distribute the values we provide over the time frame.
If we provide three values, the first value is the starting value, the second value will be reached at 50% of the elapsed time, and the third value is at 100% of the time.

 

 

Keyframes and Paths

 

Animation Types

 

- (void)addBounceAnimation {
  [mover setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:
  self.originAnimation, @"frameOrigin" , nil]];
  }

- (id)initWithFrame:(NSRect)frame {
          self = [super initWithFrame:frame];
       if (self) {
       CGFloat xInset = 3.0f * (NSWidth(frame) / 8.0f);
       CGFloat yInset = 3.0f * (NSHeight(frame) / 8.0f);
       NSRect moverFrame = NSInsetRect(frame, xInset, yInset);
       mover = [[NSImageView alloc] initWithFrame:moverFrame];
       [mover setImageScaling:NSScaleToFit];
       [mover setImage:[NSImage imageNamed:@"photo.jpg" ]];
       [self addSubview:mover];
       [self addBounceAnimation];
  }
      return self;
 }

 

 

[mover setAnimations:[NSDictionary dictionaryWithObjectsAndKeys: self.originAnimation, @"frameOrigin" , nil]];

 

frameOrigin:

这个动画的key
要和[[mover animator] setFrameOrigin:rect.origin];的
setFrameOrigin相对应,才会在setFrameOrigin方法被调用的时候,执行设置的动画

例如:
- (void)awakeFromNib

{

NSView *contentView = [[self window] contentView];

[contentView setWantsLayer:YES];

[contentView addSubview:[self currentView]];

transition = [CATransition animation];

[transition setType:kCATransitionPush];

[transition setSubtype:kCATransitionFromLeft];

NSDictionary *ani = [NSDictionary dictionaryWithObject:transition
forKey:@"subviews"];
[contentView setAnimations:ani];

}

awakeFromNib首先打开Core Animation支持(就是setWantsLayer这行)。然后把当前的参考视图currentView做为子视图加入到contentView中。由于我们已经将currentView的frameOrigin属性设置为0,0,因此不需要考虑subview的位置。

接下来我建立了一个CATransition的动画。注意我在AppDelegate中将这个动画保留为ivar。原因很明显,当动画建立时,我将它做为transition动画加入content view,key是“subviews”。这个transition动画无论在一个subview添加、删除或者替换的时候都会触发。

 

- (CAKeyframeAnimation *)originAnimation {
CAKeyframeAnimation *originAnimation = [CAKeyframeAnimation animation];
     originAnimation.path = self.heartPath;
     originAnimation.duration = 2.0f;
     originAnimation.calculationMode = kCAAnimationPaced;
     return originAnimation;
 }

 

设置动画运行路径:

     originAnimation.path = self.heartPath;

设置动画持续时间:

     originAnimation.duration = 2.0f;

设置动画方式:
     originAnimation.calculationMode = kCAAnimationPaced;

 

 

设置动画路径:

- (CGPathRef)heartPath {
      NSRect frame = [mover frame];
if(heartPath == NULL) {
              heartPath = CGPathCreateMutable();
             CGPathMoveToPoint(heartPath, NULL, NSMinX(frame), NSMinY(frame));
             CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame) - NSWidth(frame),NSMinY(frame) + NSHeight(frame) * 0.85);
             CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame),NSMinY(frame) - NSHeight(frame) * 1.5);
             CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame) + NSWidth(frame),NSMinY(frame) + NSHeight(frame) * 0.85);
             CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame), NSMinY(frame));
             CGPathCloseSubpath(heartPath);
}
       return heartPath;
}

 

这样一来,无论层的位置如何改变,它都会沿着我们创建的曲线行进,而不是默认的线性插值路径了。这个例子中还有一些细节并未交代的特别清楚,但是这至少已经帮助我们了解如何使用关键桢动画了。

 

- (void)bounce {
     NSRect rect = [mover frame];
     [[mover animator] setFrameOrigin:rect.origin];
 }

 

Recall that since we have added an animation to the animations dictionary under the frameOrigin key, the animator will find it during its search and use ours instead of the default animation.

你可能感兴趣的:(animation)