如何在动画已经动画的情况下更改动画的动画?

时间:2012-11-03 21:14:09

标签: iphone xcode animation uiimageview

所以,现在我有一个火箭在iphone 5屏幕的底部左右反弹。我希望火箭能够停止左右移动,但是一旦用户触摸屏幕就会向上移动(因此触摸屏幕会使火箭起飞)。

首先,在viewDidAppear中,我告诉编译器在2秒后运行spawnRocket方法。

spawnRocket方法中,我建立了火箭图像和框架,然后我将其添加到视图中并执行uiview动画,将火箭发送到屏幕的右侧。在uiview动画方法的finished参数中,我告诉编译器运行moveRocketLeft方法。

在moveRocketLeft方法中,我做了一个动画,它将火箭发送到屏幕的左边,在finished参数中我运行了moveRocketRight方法。

moveRocketMethod基本上是spawnRocket方法,除了我没有建立火箭图像和框架并将其添加到视图中。

所以在这之后,我尝试实现-touchesBegan:withEvent:方法。我试着简单地运行一个uiview动画,它将火箭y改为屏幕向上,而x改为用户触摸屏幕时当前所处的x。

然而,我意识到调用火箭框架并没有返回火箭在动画时的样子。它真的只是返回火箭框架完成动画时的内容。那么,要获得我想要的帧,我应该拨打layer吗?我记得在某个地方读取该图层将在动画期间返回uiimageview的实际位置。 但是,图层只有属性边界而不是框架,所以我有点困惑。

我也试过调用[self.view.layer removeAllAnimations];,然后运行一个新的动画,这会拍得尴尬,但是removeAllAnimations方法从来没有用过(而且无论如何我真的不喜欢使用它的想法,因为我听说它滞后了。)

所以任何人都知道如何实施touchesBegan:withEvent:方法,以便火箭可以正常起飞? (或者如果您认为我必须改变我的整个计划,请随时提供帮助)

    #import "ViewController.h"
    #import <QuartzCore/QuartzCore.h>
    @interface ViewController ()
    @property UIImageView *rocket;
    @end

    @implementation ViewController


    @synthesize rocket=_rocket;

    - (void)viewDidLoad
    {
        [super viewDidLoad];

    }

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view.layer removeAllAnimations];
     //   [UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];

    // this didn't work :(
    }



    -(void)viewDidAppear:(BOOL)animated{
        [self performSelector:@selector(spawnRocket) withObject:self afterDelay:2];
    }
    -(void)spawnRocket{
        self.rocket=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"default.png"]]; //places imageview right off screen
        self.rocket.frame=CGRectMake(-25, 420, 25, 40);

        [self.view addSubview:self.rocket];
        [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);}  completion:^(BOOL finished){if (finished)[self moveRocketLeft]; }];


    }

    -(void) moveRocketLeft{
        [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(0, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketRight];}];
    }

        -(void)moveRocketRight{
          [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketLeft];}];
        }
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }

    @end

1 个答案:

答案 0 :(得分:1)

这应该可以解决问题

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
    self.rocket.layer.position = rocketPresentationLayer.position;
    [UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionBeginFromCurrentState animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];
}

注1:我没有在这里放置逻辑来检查用户是否在垂直起飞时再次点击火箭。您可能需要添加BOOL或其他内容以查看用户是否成功点击了火箭,如果是,则不要再次执行垂直动画。

注2:如果将来你只想在火箭被击中时发生这种情况,你可以使用hitTest检查来有条件地调用动画。

// Get the touch
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];

// See if we hit the rocket
CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
CALayer* hitTest = [rocketPresentationLayer hitTest:touchPoint];

// If we did, then stop animation and move upwards
if (hitTest) {
    ....
}

P.S:稍微提一下,@property UIImageView *rocket;应更改为@property (nonatomic) UIImageView *rocket;。这主要是出于性能原因,因为我不希望你的火箭被多个线程访问(它不应该是UI!)。