IOS实现翻转一个View显示presentViewController

来源:互联网 发布:mac pro需要用鼠标吗 编辑:程序博客网 时间:2024/05/08 02:11

  最近看到了一个比较好看的动画效果,就是通过点击了一个View,被点击的View会被翻转过来,然后在其背面显示出另一个ViewController的内容。就像一张两面的板子被翻转一样。于是在最近的项目里面就写了下这个效果:

  







思路是这样的,先将被显示的ViewController的内容渲染到一张图片上去。

然后在window上面添加一个新的View将被点的View的内容渲染成图片后显示在此新建的View上,并且调整新建的view的位置。

隐藏被点View,然后开始反转动画。为了简单起见动画分为2步,第一步为旋转90度。第二步开始反向旋转90度,但是在开始之前将ViewController的图片显示在该View上。

最后将Viewcontroller Present出来就好了。


具体看代码吧

给UIViewController建一个Category,这样使用就很方便了。

所有代码在下面:

- (void)flipView:(UIView *)view toPresentViewController:(UIViewController *)controller completion:(void (^)(void))completion {    [self retain];    [view retain];    [controller retain];    //调整大小    UIWindow *window = [UIApplication sharedApplication].keyWindow;    CGRect frame = window.frame;    frame.size.height -= 20;    frame.origin.y = 20;    controller.view.frame = frame;    [controller.view layoutIfNeeded];    //预渲染一遍    [self presentViewController:controller animated:NO completion:nil];    [controller dismissViewControllerAnimated:NO completion:0];        //获取将要显示的 View 的 Image    UIGraphicsBeginImageContextWithOptions(controller.view.frame.size, controller.view.opaque, 0.0);    [controller.view.layer renderInContext:UIGraphicsGetCurrentContext()];    UIImage *viewControllerImage = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();    //保存被翻转的View 的 Image    UIGraphicsBeginImageContextWithOptions(view.frame.size, view.opaque, 0.0);    [view.layer renderInContext:UIGraphicsGetCurrentContext()];    UIImage *viewImgae = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();        //坐标转化    frame = view.frame;    UIView *parentView = view.superview;    if (parentView == window) {    }else{        UIView *parentParentView = parentView.superview;        while (parentParentView&&parentView&&(parentView != self.view&&parentParentView != window)) {            frame = [parentParentView convertRect:frame fromView:parentView];            parentView=parentParentView;            parentParentView = parentParentView.superview;        }    }    frame = [window convertRect:frame fromView:parentView];        //包裹旋转的View    UIView      *imageLayout=[[UIView alloc]initWithFrame:window.bounds];    UIImageView *imageView = [[UIImageView alloc]initWithFrame:frame];    [imageView setImage:viewImgae];        [imageLayout addSubview:imageView];    [window addSubview:imageLayout];        [imageLayout release];    [imageView release];            CATransform3D rotationTransform = CATransform3DMakeRotation(M_PI*1.0f/2.0f, 0, 1, 0);        [view setHidden:YES];    //投影矩阵    CATransform3D perspective = CATransform3DIdentity;    perspective.m34 = -1.0/800.0;    imageLayout .layer.sublayerTransform = perspective;    imageLayout .layer .zPosition = 2000;        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{                imageView.layer.transform = rotationTransform;            } completion:^(BOOL finished) {        [imageView setImage:viewControllerImage];        imageView.layer.transform = CATransform3DMakeRotation(-M_PI*1.0f/2.0f, 0, 1, 0);                [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{            imageView.layer.transform = CATransform3DIdentity;                        CGRect frame = window.frame;            frame.size.height -= 20;            frame.origin.y = 20;            imageView.frame =  frame;        } completion:^(BOOL finished) {            [self presentViewController:controller animated:NO completion:completion];                        [imageLayout removeFromSuperview];            [view setHidden:NO];            [view release];            [self release];            [controller release];        }];            }];}


这个版本也刚刚算能用吧,bug肯定是有的。


实际开发过程中还是有很多问题的,本人将开发中遇到的一些问题一起说下吧。

第一个就是恶心的渲染ViewController,首先从xib出来的view的frame很奇怪,有的时候只能人肉设置frame,还有就是当ViewController为Navigation时,如果给Navigation设过Appearance,如果不先经过present一下会有点显示的bug,就是appearance无效。


然后就是关于layer的zIndex的问题了,为了有立体效果,需要有点投射效果,即zIndex不能乱设。大家都知道zIndex小的layer会被zIndex大的layer遮住,但是我比较傻,一开始旋转的view总是只能显示一半,最后才发现原来会被遮住。

然后就想着提升zIndex,但是我已开始是将投射矩阵设在window上面,这样的话View的立体效果特别强,都快戳瞎狗眼了。苦于无解的时候突然想到可以用一个新的View把旋转的包起来,给那个View设置较大的zIndex,并且设置投射矩阵,结果就解决了问题。


以上