0

我有一个自定义的转场,我正在尝试与标准的“Cover Vertical”转场进行相反的操作。我认为这应该有效:

UIView *srcView = ((UIViewController *)self.sourceViewController).view;
UIView *dstView = ((UIViewController *)self.destinationViewController).view;

[dstView setFrame:CGRectMake(0, 0, srcView.window.bounds.size.width, srcView.window.bounds.size.height)];

[srcView.window insertSubview:dstView belowSubview:srcView];

[UIView animateWithDuration:0.3
     animations:^{
         srcView.center = CGPointMake(srcView.center.x - srcView.frame.size.width, srcView.center.y);
     }
     completion:^(BOOL finished){
         [srcView removeFromSuperview];
     }
 ];

问题是目标视图以纵向显示,即使应用程序中的所有其他视图都是横向的。此外,x 和 y 坐标是相反的。为什么会这样?

我已经shouldAutorotateToInterfaceOrientation在每个视图控制器中进行了设置,但这并没有帮助。我可以用 旋转视图CGAffineTransformMakeRotation,但这似乎不是正确的做法;一方面,坐标仍然会颠倒。

更新:

我尝试使用CGAffineTransformRotate旋转视图,但它看起来很荒谬。大多数背景显示为黑色。我不认为这是它应该工作的方式。

4

5 回答 5

3

由于在控制器交换之前我无法获得目标视图的正确方向和框架,因此我确实颠倒了这个过程:

  1. 将源视图保存为图像(请参阅使用自定义动画删除自定义 UIStoryboardSegue);
  2. 切换当前控制器 [presentViewController: ...];
  3. 然后,使用嵌入保存的源图像的(现在正确的)目标视图制作动画。

这是完整的代码:

#include <QuartzCore/QuartzCore.h>

@implementation HorizontalSwipingSegue

- (void) perform {
    UIViewController *source = self.sourceViewController;
    UIViewController *destination = self.destinationViewController;    
    UIView *sourceView = source.view;
    UIView *destinationView = destination.view;

    // Create a UIImageView with the contents of the source
    UIGraphicsBeginImageContext(sourceView.bounds.size);
    [sourceView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *sourceImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImageView *sourceImageView = [[UIImageView alloc] initWithImage:sourceImage];

    [[self sourceViewController] presentViewController:[self destinationViewController] animated:NO completion:NULL];

    CGPoint destinationViewFinalCenter = CGPointMake(destinationView.center.x, destinationView.center.y);
    CGFloat deltaX = destinationView.frame.size.width;
    CGFloat deltaY = destinationView.frame.size.height;

    switch (((UIViewController *)self.sourceViewController).interfaceOrientation) {
       case UIDeviceOrientationPortrait:
            destinationView.center = CGPointMake(destinationView.center.x - deltaX, destinationView.center.y);                
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaX, sourceImageView.center.y);
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            destinationView.center = CGPointMake(destinationView.center.x + deltaX, destinationView.center.y);
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaX, sourceImageView.center.y);
            break;
        case UIDeviceOrientationLandscapeLeft:
            destinationView.center = CGPointMake(destinationView.center.x, destinationView.center.y - deltaY);                
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaY, sourceImageView.center.y);
            break;
        case UIDeviceOrientationLandscapeRight:
            destinationView.center = CGPointMake(destinationView.center.x, destinationView.center.y + deltaY);
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaY, sourceImageView.center.y);
            break;
    }

    [destinationView addSubview:sourceImageView];

    [UIView animateWithDuration:0.6f
                     animations:^{
                         destinationView.center = destinationViewFinalCenter; 
                     }
                     completion:^(BOOL finished){
                         [sourceImageView removeFromSuperview];
                     }];
}

@end
于 2012-11-18T11:43:54.000 回答
1

Apparently, it was much easier than I thought to do the segue I wanted. Here's is what worked:

- (void)perform {
    UIViewController *src = (UIViewController *)self.sourceViewController;
    [src dismissViewControllerAnimated:YES completion:^(void){ [src.view removeFromSuperview]; }];
}

Hopefully this helps someone else.

于 2012-08-06T18:01:30.420 回答
1

更新答案:

确保您正确设置了 dstView 的框架。我认为你会更好地使用:

dstView.frame = srcView.frame;

代替:

[dstView setFrame:CGRectMake(0, 0, srcView.window.bounds.size.width, srcView.window.bounds.size.height)];

bounds属性不会以相同的方式frame对方向变化做出反应。

于 2012-07-26T16:30:34.410 回答
0

代替

[srcView insertSubview:dstView belowSubview:srcView];

[srcView insertSubview:dstView atIndex:0];
于 2012-07-26T16:35:41.313 回答
0

如果您只是将另一个视图控制器的视图添加到您的视图层次结构中,则该视图控制器不会获取有关设备方向的任何信息,因此它将以其默认配置显示视图。您还需要使用此处描述的包含方法将视图控制器添加到视图控制器层次结构中。完成后,您还需要将其从层次结构中删除。

关于这个主题也有几个很好的 WWDC 演讲,一个来自 2011 年,名为“实现视图控制器遏制”,另一个来自今年,视图控制器的演变。

于 2012-07-26T16:46:16.473 回答