使用自定义动画在视图的两个状态之间设置动画

时间:2010-07-01 12:40:38

标签: ios objective-c cocoa-touch cocoa core-animation

我想在视图的两个状态之间制作动画。比如说,我有一个带标签的视图,当我更改标签的文本时,动画会将更改呈现为页面翻转。

现在,您可以使用[UIView setAnimationTransition:forView:cache:]

执行此操作
- (IBAction)nextPage {
    [UIView beginAnimation:nil context:nil];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:pageView cache:NO];
    label.text = @"page 2";
    [UIView commitAnimations];
}

- (IBAction)previousPage {
    [UIView beginAnimation:nil context:nil];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:pageView cache:NO];
    label.text = @"page 1";
    [UIView commitAnimations];
}

...但是你不能使用你自己的自定义动画,你会坚持使用内置的动画(它们很好但是它们不适合我的需要)。

所以另一个选择是在视图的图层中添加CAAnimation

- (IBAction)nextPage {
    CAAnimation *animation = [self animationWithDuration:1 forward:NO];
    [pageView.layer addAnimation:animation forKey:@"pageTransition"];
    label.text = @"page 2";
}

- (IBAction)previousPage {
    CAAnimation *animation = [self animationWithDuration:1 forward:YES];
    [pageView.layer addAnimation:animation forKey:@"pageTransition"];
    label.text = @"page 1";
}

然后您可以自由设置Core Animation允许您执行的任何动画。如果我定义CATransition动画,例如kCATransitionReveal,则效果很好:“页面2”状态下的视图在“页面1”状态下显示为滑出时。

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionReveal];
    [animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];

    animation.duration = duration; 
    return animation; 
}

但是当我将动画定义为例如CABasicAnimation时,只能看到一个视图状态。

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0 / -1000;
    transform = CATransform3DRotate(transform, M_PI, 0.0f, 1.0f, 0.0f);
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    if(forward) {
        animation.fromValue = [NSValue valueWithCATransform3D:transform];
    } else {
        animation.toValue = [NSValue valueWithCATransform3D:transform];
    }

    animation.duration = duration; 
    return animation; 
}

相反,我希望“页面1”状态中的视图在动画结束时保持可见,而“页面2”状态中的视图进入框架,就像它使用过渡动画一样。

当然,我总是可以弄乱复制视图并让一个看起来像一个兄弟视图,同时我为最前面的一个制作动画并在完成后从superview中删除它...但是必须有一个更直接的方法来实现这一点相当简单的动画效果,而不会弄乱视图。

可能有什么东西告诉这个层,但后来我不知道是什么,那就是我需要你帮助的地方,伙计们:)

谢谢!

3 个答案:

答案 0 :(得分:1)

我最近在控制器中的子视图之间进行了自定义幻灯片转换。我的方法是获取视图输出和视图的位图,将它们添加到视图并为该视图设置动画。最后,您可以删除转换视图并显示视图。这是转换方法的片段:

-(void) transitionToView:(UIView *)viewIn lastView:(UIView *)viewOut slideRight:(BOOL)isRight { 
UIGraphicsBeginImageContext(viewOut.frame.size);

UIImageView *bitmapOut = [[UIImageView alloc] initWithFrame: viewOut.frame];

[viewOut.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewOutImage = UIGraphicsGetImageFromCurrentImageContext();   
UIGraphicsEndImageContext();
bitmapOut.image = viewOutImage;

UIImageView *bitmapIn = [[UIImageView alloc] initWithFrame: viewIn.frame ];
bitmapIn.frame = CGRectMake(isRight ? 320 : -320, bitmapIn.frame.origin.y, bitmapIn.frame.size.width, bitmapIn.frame.size.height);
UIGraphicsBeginImageContext(viewIn.frame.size);

[viewIn.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewInImage = UIGraphicsGetImageFromCurrentImageContext();   
UIGraphicsEndImageContext();

bitmapIn.image = viewInImage;

[self.view addSubview:transitionContainer];

[transitionContainer addSubview:bitmapIn];
[transitionContainer addSubview:bitmapOut];

[self removeAllViews];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(swapViewsAtEndOfTransition:)];
transitionContainer.frame = CGRectMake(isRight ? -320 : 320, 0, 640, 411);
[UIView commitAnimations];

[bitmapOut release]; bitmapOut = nil;
[bitmapIn release]; bitmapIn = nil;}

然后,在swapViewsAtEndOfTransition选择器中,您可以相应地更新视图。

答案 1 :(得分:0)

好吧,您可以创建一个图层,将其内容设置为代表您的视图最终状态的图像,而不是将动画应用于此图层。动画完成后,您可以删除图层并切换视图状态。

我认为这比实例化整个观点更有效。

答案 2 :(得分:0)

岁月已过,但我想我找到了适合你的解决方案。只需使用kCATransitionPush代替kCATransitionReveal即可。像这样:

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionPush];
    [animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];

    animation.duration = duration; 
    return animation; 
}