两个UIView之间的自定义转场

6
我有两个视图"A"和"B"。A浮动在窗口中间(不是全屏)。B是全屏的,将替换A。我想编写一个自定义转换,将A翻转以显示B的背面,但同时缩放翻转矩形,以便翻转完成后,B变成全屏。
我尝试使用transitionFromView:toView:duration:options:completion提供的翻转过渡效果,但我只能让它翻转整个屏幕,而不是从A的框架开始并以B的框架结束。
我知道可以对视图的图层进行类似3D的变换,但我不确定应该使用哪一组动画API来实现这一点。我尝试的一件事是在transitionWithView:duration:options:animations:completion的动画块中修改视图的图层属性,但这并没有起作用,因为它似乎只尊重视图属性修改。
有人可以指点我正确的方向吗?非常感谢。
更新:这里是我的代码,用于实现此效果。您可以在此处查看其操作视频:http://www.youtube.com/watch?v=-xNMD2fGRwg
CGRect frame = [[UIApplication easybookDelegate] rootViewController].view.bounds ;
float statusHeight = [UIApplication sharedApplication].statusBarFrame.size.height ;
frame.origin.y = statusHeight ;
frame.size.height -= statusHeight ;
self.view.frame = frame ; // self.view is view "B"

// Put the snapshot as thet topmost view of our view
UIImageView *imageView = [[UIImageView alloc] initWithImage:image] ; // image is a snapshot of view "A"
imageView.frame = self.view.bounds ;
[self.view addSubview:imageView] ;
[self.view bringSubviewToFront:imageView] ;

// Pre-transform our view (s=target/current, d=target-current)
CGAffineTransform transform = CGAffineTransformIdentity ;

// Translate our view
CGPoint center  = CGPointMake(screenOrigin.x + (image.size.width/2.0), screenOrigin.y + (image.size.height/2.0)) ;
float dX = center.x - self.view.center.x ;
float dY = center.y - self.view.center.y ;
NSLog( @"dx: %f, dy: %f" , dX, dY ) ;

transform = CGAffineTransformTranslate(transform, dX, dY) ;

// Scale our view
float scaleWFactor = image.size.width / self.view.frame.size.width ;
float scaleHFactor = image.size.height / self.view.frame.size.height ;
transform = CGAffineTransformScale(transform,scaleWFactor, scaleHFactor) ;

self.view.transform = transform ;

[[[UIApplication easybookDelegate] rootViewController].view addSubview:self.view] ;

// Perform the animation later since implicit animations don't seem to work due to
// view "B" just being added above and hasn't had a chance to become visible. Right now
// this is just on a timer for debugging purposes. It'll probably be moved elsewhere, probably
// to view "B"'s -didMoveToSuperview
double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [UIView transitionWithView:self.view duration:3 options:UIViewAnimationOptionTransitionFlipFromRight| UIViewAnimationOptionCurveEaseOut animations:^(void) 
        {
        [imageView removeFromSuperview] ;
        self.view.transform = CGAffineTransformIdentity ;
        } 
        completion:^(BOOL finished){
                [self.view removeFromSuperview] ;
                [navController presentModalViewController:self animated:NO] ;
        }] ;
});

[imageView release];


1
Youtube账号已删除。 - k06a
这是我自从最初发布后编写的一些代码,可以执行该效果(我已经在几个应用程序中使用它来执行):https://github.com/leftspin/IVM-Awesomesauce - leftspin
6个回答

3

我以前做过这个。以下是我完成它的要点:

  1. 屏幕上显示视图A
  2. 创建视图B,给它一个使其全屏的框架,但暂时不要将其添加到屏幕上
  3. 视图B具有UIImageView作为其最顶部的视图
  4. 捕获视图A的UIImage,并将其设置为视图B的图像视图的图像

    UIGraphicsBeginImageContext(view.bounds.size); 
    [viewA.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    viewB.imageView.image = image;
    
  5. 设置视图B的变换(缩放和平移),使其缩小到视图A的大小,并定位在屏幕上的视图A位置

  6. 将视图B添加到屏幕上
  7. 此时,用户还没有注意到任何变化,因为视图B看起来与视图A完全相同
  8. 现在开始一个动画块,在其中您可以
    • 设置[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft forView:ViewB
    • 将视图B的变换设置为CGAffineTransformIdentity
    • 从视图B中删除视图B的图像视图

结果是一种动画效果,看起来像视图A翻转并缩放以填满屏幕,同时显示出视图B的另一面。


这难道不只是将视图缩放吗?我没看到翻转发生在哪里... - leftspin
实际上,看起来你不能将视图的变换设置为进行3D翻转,因为它是一个2D变换矩阵。 - leftspin
你可以通过设置动画的animationTransition值来实现翻转效果。我会编辑这个答案... - CharlieMezak
顺便说一句,这帮了我很多,所以我会把赏金分配给你,但我仍然希望能够让动画的“前”部分与“后”部分一起缩放。 - leftspin
我看到你正在使用块来处理动画。这可能是现在应该做的事情,但当我成功地完成它时,我使用了旧的beginAnimations / commitAnimations消息。我会回去找我的代码并看看我能找到什么。 - CharlieMezak
显示剩余3条评论

1

请检出此 SVN 仓库:

http://boondoggle.atomicwang.org/lemurflip/

这将翻转两个视图。


1

这是我为您制作的一个简单示例 :-) 从它开始...试着理解它...阅读文档,然后您将能够做您想要的事情 ;-)

- (void)moveTable:(UITableView *)table toPoint:(CGPoint)point excursion:(CGFloat)excursion {

[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.5];
[table setCenter:point];

// scaling
CABasicAnimation *scalingAnimation = (CABasicAnimation *)[table.layer animationForKey:@"scaling"];
if (!scalingAnimation)
{
    scalingAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    scalingAnimation.duration=0.5/2.0f;
    scalingAnimation.autoreverses=YES;
    scalingAnimation.removedOnCompletion = YES;
    scalingAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    scalingAnimation.fromValue=[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0, 0.0, 0.0)];
    scalingAnimation.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(excursion, 0.0, 0.0)];
}
[table.layer addAnimation:scalingAnimation forKey:@"scaling"];
[UIView commitAnimations];

}


为什么要将翻译动画分配给“缩放”键,而“缩放”键与视图的翻译有什么关系? - leftspin

0

尝试像这样做。只要A的框架不是全屏的,那么动画就应该翻转A。在翻转过渡中向视图添加子视图时,它将被添加到该视图的后面,因此您需要修改视图A的框架。

[UIView beginAnimations:@"flipopen" context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self cache:TRUE];
[a addSubview:b];
a.frame = b.frame;
[UIView commitAnimations];

0

我假设你只想在翻转和缩放图像视图时更改其图像。 以下代码使用默认动画翻转图像视图,将其缩放到另一个视图的框架并设置图像:

[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.imageViewA cache:NO];
[UIView setAnimationDuration:2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationFinished:)];
self.imageViewA.frame = self.imageViewB.frame;
self.imageViewA.image = self.imageViewB.image;
[UIView commitAnimations];

如果您希望再次显示A视图作为您的小浮动视图,并使用其他图像,您可以在AnimationDidStopSelector方法中设置其框架和图像,而无需动画块。
-(void)animationFinished:(id)context
{
    self.imageViewA.frame = tinyRect;
    self.imageViewA.image = [UIImage imageNamed:@"a.jpg"];
}

其中tinyRect是浮动视图A的原始框架。


0

这个方案还有点粗糙,但是我使用块动画实现了以下功能:翻转视图、居中并全屏显示。

// the view on the other side of the card
UIView* redView = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, viewToFlip.frame.size.width, viewToFlip.frame.size.height)];
redView.backgroundColor = [UIColor redColor];

// add a green square to the red view so we have something else to look at
UIView* greenSquare = [[UIView alloc]initWithFrame:CGRectMake(10.0, 10.0, 20.0, 20.0)];
greenSquare.backgroundColor = [UIColor greenColor];    
[redView addSubview:greenSquare];

// the flip animation
[UIView animateWithDuration:0.25
                      delay:0.0
                    options:UIViewAnimationCurveLinear
                 animations:^{

                     // rotate 90 degrees
                     [viewToFlip.layer setTransform: CATransform3DRotate(viewToFlip.layer.transform, -M_PI/2, 0.0, 1.0, 0.0)];

                 } 
                 completion:^(BOOL finished){

                     // now that we're 90 degrees, swap one view for the other
                     // but if we add it now, the view will be backwards, so flip the original view back
                     [viewToFlip.layer setTransform: CATransform3DRotate(viewToFlip.layer.transform, M_PI, 0.0, 1.0, 0.0)];
                     [viewToFlip addSubview:redView];

                     // now let's continue our rotation
                     [UIView animateWithDuration:0.25
                                           delay:0.0
                                         options:UIViewAnimationCurveLinear
                                      animations:^{

                                          // rotate the last 90 degrees
                                          [viewToFlip.layer setTransform: CATransform3DRotate(viewToFlip.layer.transform, -M_PI/2, 0.0, 1.0, 0.0)];

                                      } 
                                      completion:^(BOOL finished){

                                          [UIView animateWithDuration:0.25
                                                                delay:0.0
                                                              options:UIViewAnimationCurveLinear
                                                           animations:^{

                                                               // animate the views to the center of the screen and adjust their bounds to fill up the screen
                                                               [viewToFlip setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
                                                               [viewToFlip setBounds:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
                                                               [redView setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
                                                               [redView setBounds:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
                                                           }
                                                           completion:nil];


                                      }];

                 }];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接