两个UIViews之间的自定义转换

时间:2011-04-01 09:28:59

标签: iphone uiview core-animation

我有两个观点“A”和“B”。在窗口中间浮动(它不是全屏)。 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];

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];

6 个答案:

答案 0 :(得分: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看起来与View A
  8. 完全相同
  9. 现在开始一个动画块,你在其中
    • 设置[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft forView:ViewB
    • 将View B的转换设置为CGAffineTransformIdentity
    • 从View B中删除View B的imageview
  10. 结果是一个看起来像View A的动画正在翻转和缩放以填充屏幕,View B作为对面。

答案 1 :(得分:1)

结帐此svn存储库:

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

这会翻转两个视图。

答案 2 :(得分: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];

}

答案 3 :(得分: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];

答案 4 :(得分: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视图的原始帧。

答案 5 :(得分: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];


                                      }];

                 }];