如何控制动画

层级关系时间

在第三章“图层几何学”中,你已经了解到每个图层是如何相对在图层树中的父图层定义 它的坐标系的。动画时间和它类似,每个动画和图层在时间上都有它自己的层级概念,相对于它的父亲来测量。对图层调整时间将会影响到它本身和子图层的动画, 但不会影响到父图层。另一个相似点是所有的动画都被按照层级组合(使用CAAnimationGroup实例)。

对CALayer或者 CAGroupAnimation调整duration和repeatCount/repeatDuration属性并不会影响到子动画。但是 beginTime,timeOffset和speed属性将会影响到子动画。然而在层级关系中,beginTime指定了父图层开始动画(或者组合关系 中的父动画)和对象将要开始自己动画之间的偏移。类似的,调整CALayer和CAGroupAnimation的speed属性将会对动画以及子动画速 度应用一个缩放的因子。

全局时间和本地时间

CoreAnimation 有一个全局时间的概念,也就是所谓的马赫时间(“马赫”实际上是iOS和Mac OS系统内核的命名)。马赫时间在设备上所有进程都是全局的--但是在不同设备上并不是全局的--不过这已经足够对动画的参考点提供便利了,你可以使用 CACurrentMediaTime函数来访问马赫时间:


1

CFTimeInterval time = CACurrentMediaTime();

这个函数返回的值其实无关紧要(它返回了设备自从上次启动后的秒数,并不是你所关心的),它真实的作用在于对动画的时间测量提供了一个相对值。注意当设备休眠的时候马赫时间会暂停,也就是所有的CAAnimations(基于马赫时间)同样也会暂停。

因此马赫时间对长时间测量并不有用。比如用CACurrentMediaTime去更新一个实时闹钟并不明智。(可以用[NSDate date]代替,就像第三章例子所示)。

每 个CALayer和CAAnimation实例都有自己本地时间的概念,是根据父图层/动画层级关系中的beginTime,timeOffset和 speed属性计算。就和转换不同图层之间坐标关系一样,CALayer同样也提供了方法来转换不同图层之间的本地时间。如下:


1

2

- (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(CALayer *)l; 

- (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l;

当用来同步不同图层之间有不同的speed,timeOffset和beginTime的动画,这些方法会很有用。

暂停,倒回和快进

设 置动画的speed属性为0可以暂停动画,但在动画被添加到图层之后不太可能再修改它了,所以不能对正在进行的动画使用这个属性。给图层添加一个 CAAnimation实际上是给动画对象做了一个不可改变的拷贝,所以对原始动画对象属性的改变对真实的动画并没有作用。相反,直接用 -animationForKey:来检索图层正在进行的动画可以返回正确的动画对象,但是修改它的属性将会抛出异常。

如果移除图层正在进行的动画,图层将会急速返回动画之前的状态。但如果在动画移除之前拷贝呈现图层到模型图层,动画将会看起来暂停在那里。但是不好的地方在于之后就不能再恢复动画了。

一个简单的方法是可以利用CAMediaTiming来暂停图层本身。如果把图层的speed设置成0,它会暂停任何添加到图层上的动画。类似的,设置speed大于1.0将会快进,设置成一个负值将会倒回动画。

通过增加主窗口图层的speed,可以暂停整个应用程序的动画。这对UI自动化提供了好处,我们可以加速所有的视图动画来进行自动化测试(注意对于在主窗口之外的视图并不会被影响,比如UIAlertview)。可以在app delegate设置如下进行验证:


1

self.window.layer.speed = 100;

你也可以通过这种方式来减速,但其实也可以在模拟器通过切换慢速动画来实现。

手动动画

timeOffset一个很有用的功能在于它可以让你手动控制动画进程,通过设置speed为0,可以禁用动画的自动播放,然后来使用timeOffset来来回显示动画序列。这可以使得运用手势来手动控制动画变得很简单。

举个简单的例子:还是之前关门的动画,修改代码来用手势控制动画。我们给视图添加一个UIPanGestureRecognizer,然后用timeOffset左右摇晃。

因为在动画添加到图层之后不能再做修改了,我们来通过调整layer的timeOffset达到同样的效果(清单9.4)。

清单9.4 通过触摸手势手动控制动画

@interface ViewController ()<CAMediaTiming>
{
    CALayer *doorLayer;
}
@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftConstraint;
@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    doorLayer = [CALayer layer];
    doorLayer.frame = CGRectMake(0, 0, 128, 256);
    doorLayer.position = self.view.center;
    doorLayer.anchorPoint = CGPointMake(0, 0.5);
    doorLayer.contents = (__bridge id)[UIImage imageNamed: @"bjl_list_02"].CGImage;
    [self.view.layer addSublayer:doorLayer];
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    self.view.layer.sublayerTransform = perspective;
    
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] init];
    [pan addTarget:self action:@selector(pan:)];
    [self.view addGestureRecognizer:pan];
    //pause all layer animations
    doorLayer.speed = 0.0;
    //apply swinging animation (which won‘t play because layer is paused)
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 1.0;
    [doorLayer addAnimation:animation forKey:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{

}
- (void)pan:(UIPanGestureRecognizer *)pan
{
    //get horizontal component of pan gesture
    CGFloat x = [pan translationInView:self.view].x;
    //convert from points to animation duration //using a reasonable scale factor
    x /= 200.0f;
    //update timeOffset and clamp result
    CFTimeInterval timeOffset = doorLayer.timeOffset;
    timeOffset = MIN(0.999, MAX(0.0, timeOffset - x));
    doorLayer.timeOffset = timeOffset;
    //reset pan gesture
    [pan setTranslation:CGPointZero inView:self.view];
}

时间: 2024-11-05 17:25:57

如何控制动画的相关文章

WPF控制动画开始、停止、暂停和恢复

1.闲言 好久也没更新一博客了,自己有点发懒,同时确实这几个月来也有点忙.风机监测软件,项目中,有这样一个小需求:正常风机在旋转的时候,上位机软要做一个风机的图片,让它不停地旋转,一但检测到下面风机停止了,上位机软件界面的风机图片也要跟着停止,并且风机图片的旋转速度最好是能够与真实的速度成比例关系,这样软件才更有逼格一点.就是实现这样一个效果,看下图1,左边是一个状态指示,没有做动画,只是做了一个图片的切换,效果还看得过去吧. 图1 风机旋转动画 2.动画制作 在WPF做动画前,首先超码得有3个

利用手势控制动画的进度

最近在研究一个项目,利用手势控制动画的进度,发现简单的还可以,如果遇到了复杂的情况就比较麻烦了,ios7新出了一个特性,可以利用NavigationController的自定义转场动画,提供进度来控制. //这个方法控制转场动画的进度 - (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController               

UIView下使用Animation控制动画

UIView下使用Animation控制动画 动画效果是IOS界面重要的特色之一,其中CAAnimation是所有动画对象的抽象父类,作为新人,使用较多的是UIView下的动画方法(类方法).使用UIView下的动画,有下面几个方法. 方法一:设置beginAnimations 其中memberView为需要添加的子视图的视图,mivc.view为子视图,在使用的时候,需要将这两个地方替换 [cpp] view plaincopyprint? [UIView beginAnimations:@"

使用as3控制动画

1.建立按钮元件 2.在属性面板使用英文为按钮元件命名,例如playButton 3.建立函数,例如 function startMovie(event:MouseEvent):void {  this.play();     } 4.为实例即按钮元件绑定事件和处理函数 playButton.addEventListener(MouseEvent.CLICK, startMovie); 使用as3控制动画

使用as3控制动画的播放与暂停

1.需要两个按钮元件 2.在属性面板为两个按钮元件分别命名为pausebutton与playButton 3.代码 stop(); pausebutton.visible = false; playButton.visible = true; function startMovie(event:MouseEvent):void { this.play(); playButton.visible = false; pausebutton.visible = true; } function sto

Unity3D之Mecanim动画系统学习笔记(六):使用脚本控制动画

控制人物动画播放 这里我重新弄了一个简单的场景和新的Animator Controller来作为示例. 下面先看看Animator Controller的配置: 人物在站立状态只能进入走路,走路只能进入奔跑或返回站立,奔跑只能进入跳跃或返回走路,跳跃则只能返回奔跑. 参数方面为两个参数: Float类型的moveSpeed: Trigger类型的Jump: 连线直接的转换条件为:moveSpeed大于0.1进入走路,走路moveSpeed大于0.9进入奔跑小于0.1返回站立,奔跑moveSpee

Silverlight代码编写对控件的PlaneProjection.RotationY属性控制动画

Canvas c; void btnDraw_Click(object sender, RoutedEventArgs e) { Storyboard story = new Storyboard(); DoubleAnimation yAnimation = new DoubleAnimation(); yAnimation.From = 0.5; yAnimation.To = 100; yAnimation.Duration = new Duration(TimeSpan.FromSeco

Unity3d Animator控制动画按帧运行

昨天同事想控制一个角色射箭动画,在拉弓的时候想用代码控制人物拉弓的整个过程,查了一下API,方法很简单Animator.StartPlay()(http://wiki.ceeger.com/script:unityengine:classes:animator:animator.startplayback),使用Animator.StopPlayback()停止动画器播放模式.当播放停止时,Avatar恢复从游戏逻辑获得控制权 Example: 1 using UnityEngine; 2 us

关于Animator控制动画的正播和倒播

官方给出这样的解释: ah you want to play the clip in rewind mode, sorry I misunderstood your question. You can only set the Animator state speed in the editor. So if you need to play a clip both in forward or rewind mode you need to create two different state